Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next
authorDavid S. Miller <davem@davemloft.net>
Wed, 10 Sep 2014 19:46:32 +0000 (12:46 -0700)
committerDavid S. Miller <davem@davemloft.net>
Wed, 10 Sep 2014 19:46:32 +0000 (12:46 -0700)
Pablo Neira Ayuso says:

====================
nf-next pull request

The following patchset contains Netfilter/IPVS updates for your
net-next tree. Regarding nf_tables, most updates focus on consolidating
the NAT infrastructure and adding support for masquerading. More
specifically, they are:

1) use __u8 instead of u_int8_t in arptables header, from
   Mike Frysinger.

2) Add support to match by skb->pkttype to the meta expression, from
   Ana Rey.

3) Add support to match by cpu to the meta expression, also from
   Ana Rey.

4) A smatch warning about IPSET_ATTR_MARKMASK validation, patch from
   Vytas Dauksa.

5) Fix netnet and netportnet hash types the range support for IPv4,
   from Sergey Popovich.

6) Fix missing-field-initializer warnings resolved, from Mark Rustad.

7) Dan Carperter reported possible integer overflows in ipset, from
   Jozsef Kadlecsick.

8) Filter out accounting objects in nfacct by type, so you can
   selectively reset quotas, from Alexey Perevalov.

9) Move specific NAT IPv4 functions to the core so x_tables and
   nf_tables can share the same NAT IPv4 engine.

10) Use the new NAT IPv4 functions from nft_chain_nat_ipv4.

11) Move specific NAT IPv6 functions to the core so x_tables and
    nf_tables can share the same NAT IPv4 engine.

12) Use the new NAT IPv6 functions from nft_chain_nat_ipv6.

13) Refactor code to add nft_delrule(), which can be reused in the
    enhancement of the NFT_MSG_DELTABLE to remove a table and its
    content, from Arturo Borrero.

14) Add a helper function to unregister chain hooks, from
    Arturo Borrero.

15) A cleanup to rename to nft_delrule_by_chain for consistency with
    the new nft_*() functions, also from Arturo.

16) Add support to match devgroup to the meta expression, from Ana Rey.

17) Reduce stack usage for IPVS socket option, from Julian Anastasov.

18) Remove unnecessary textsearch state initialization in xt_string,
    from Bojan Prtvar.

19) Add several helper functions to nf_tables, more work to prepare
    the enhancement of NFT_MSG_DELTABLE, again from Arturo Borrero.

20) Enhance NFT_MSG_DELTABLE to delete a table and its content, from
    Arturo Borrero.

21) Support NAT flags in the nat expression to indicate the flavour,
    eg. random fully, from Arturo.

22) Add missing audit code to ebtables when replacing tables, from
    Nicolas Dichtel.

23) Generalize the IPv4 masquerading code to allow its re-use from
    nf_tables, from Arturo.

24) Generalize the IPv6 masquerading code, also from Arturo.

25) Add the new masq expression to support IPv4/IPv6 masquerading
    from nf_tables, also from Arturo.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
1508 files changed:
Documentation/DocBook/drm.tmpl
Documentation/SubmittingPatches
Documentation/devicetree/bindings/input/atmel,maxtouch.txt
Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
Documentation/devicetree/bindings/mfd/tc3589x.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/gpmc-nand.txt
Documentation/devicetree/bindings/net/broadcom-mdio-unimac.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/broadcom-sf2.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/can/m_can.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/can/rcar_can.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/dsa/dsa.txt
Documentation/devicetree/bindings/net/emac_rockchip.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/socfpga-dwmac.txt
Documentation/devicetree/bindings/net/stmmac.txt
Documentation/devicetree/bindings/pci/designware-pcie.txt
Documentation/devicetree/bindings/pci/ti-pci.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/qcom,apq8064-pinctrl.txt
Documentation/devicetree/bindings/regulator/tps65090.txt
Documentation/devicetree/bindings/sound/adi,axi-spdif-tx.txt
Documentation/dma-buf-sharing.txt
Documentation/filesystems/Locking
Documentation/filesystems/nfs/nfs-rdma.txt
Documentation/filesystems/seq_file.txt
Documentation/gpio/consumer.txt
Documentation/i2c/dev-interface
Documentation/kdump/kdump.txt
Documentation/laptops/00-INDEX
Documentation/laptops/toshiba_haps.txt [new file with mode: 0644]
Documentation/misc-devices/lis3lv02d
Documentation/networking/filter.txt
Documentation/networking/ip-sysctl.txt
Documentation/networking/timestamping.txt
Documentation/networking/timestamping/Makefile
Documentation/networking/timestamping/txtimestamp.c [new file with mode: 0644]
Documentation/power/regulator/consumer.txt
Documentation/power/regulator/design.txt
Documentation/power/regulator/machine.txt
Documentation/power/regulator/overview.txt
Documentation/power/regulator/regulator.txt
Documentation/sysctl/net.txt
Documentation/this_cpu_ops.txt
Documentation/x86/tlb.txt
MAINTAINERS
Makefile
arch/alpha/include/asm/io.h
arch/alpha/include/asm/unistd.h
arch/alpha/include/uapi/asm/unistd.h
arch/alpha/kernel/systbls.S
arch/arc/mm/cache_arc700.c
arch/arm/Kconfig
arch/arm/boot/dts/am4372.dtsi
arch/arm/boot/dts/am437x-gp-evm.dts
arch/arm/boot/dts/am43x-epos-evm.dts
arch/arm/boot/dts/at91rm9200.dtsi
arch/arm/boot/dts/at91sam9g20.dtsi
arch/arm/boot/dts/dra7-evm.dts
arch/arm/boot/dts/dra7.dtsi
arch/arm/boot/dts/exynos4412-odroid-common.dtsi
arch/arm/boot/dts/imx53-qsrb.dts
arch/arm/boot/dts/imx53.dtsi
arch/arm/boot/dts/imx6dl-hummingboard.dts
arch/arm/boot/dts/imx6q-dmo-edmqmx6.dts
arch/arm/boot/dts/imx6qdl-cubox-i.dtsi
arch/arm/boot/dts/imx6qdl-microsom-ar8035.dtsi
arch/arm/boot/dts/imx6sx-pinfunc.h
arch/arm/boot/dts/omap3-beagle.dts
arch/arm/boot/dts/omap3-n900.dts
arch/arm/boot/dts/omap3430-sdp.dts
arch/arm/boot/dts/omap3xxx-clocks.dtsi
arch/arm/boot/dts/omap54xx-clocks.dtsi
arch/arm/boot/dts/r8a7791-koelsch.dts
arch/arm/boot/dts/rk3066a-bqcurie2.dts
arch/arm/boot/dts/rk3188-radxarock.dts
arch/arm/boot/dts/rk3188.dtsi
arch/arm/boot/dts/rk3xxx.dtsi
arch/arm/boot/dts/ste-snowball.dts
arch/arm/boot/dts/sun6i-a31.dtsi
arch/arm/boot/dts/tegra30-apalis.dtsi
arch/arm/boot/dts/tegra30-colibri.dtsi
arch/arm/boot/dts/twl6030.dtsi
arch/arm/boot/dts/vf610-twr.dts
arch/arm/common/edma.c
arch/arm/include/asm/cacheflush.h
arch/arm/include/asm/cputype.h
arch/arm/include/asm/elf.h
arch/arm/include/asm/smp_plat.h
arch/arm/kernel/entry-header.S
arch/arm/kernel/module.c
arch/arm/kvm/handle_exit.c
arch/arm/kvm/init.S
arch/arm/mach-at91/board-dt-rm9200.c
arch/arm/mach-bcm/Makefile
arch/arm/mach-bcm/brcmstb.h [deleted file]
arch/arm/mach-bcm/headsmp-brcmstb.S [deleted file]
arch/arm/mach-bcm/platsmp-brcmstb.c [deleted file]
arch/arm/mach-exynos/mcpm-exynos.c
arch/arm/mach-imx/Kconfig
arch/arm/mach-imx/Makefile
arch/arm/mach-imx/clk-imx6q.c
arch/arm/mach-imx/suspend-imx6.S
arch/arm/mach-omap2/board-flash.c
arch/arm/mach-omap2/gpmc-nand.c
arch/arm/mach-omap2/gpmc.c
arch/arm/mach-omap2/id.c
arch/arm/mach-omap2/omap_device.c
arch/arm/mach-omap2/omap_hwmod.c
arch/arm/mach-omap2/omap_hwmod_7xx_data.c
arch/arm/mach-omap2/soc.h
arch/arm/mach-shmobile/Kconfig
arch/arm/mach-shmobile/clock-r8a7790.c
arch/arm/mach-shmobile/clock-r8a7791.c
arch/arm/mach-shmobile/clock-sh73a0.c
arch/arm/mach-vexpress/spc.c
arch/arm/mm/abort-ev6.S
arch/arm/mm/abort-ev7.S
arch/arm/net/bpf_jit_32.c
arch/arm64/Makefile
arch/arm64/configs/defconfig
arch/arm64/crypto/sha2-ce-glue.c
arch/arm64/include/asm/hw_breakpoint.h
arch/arm64/include/asm/processor.h
arch/arm64/include/asm/ptrace.h
arch/arm64/include/asm/sparsemem.h
arch/arm64/include/asm/unistd.h
arch/arm64/include/asm/unistd32.h
arch/arm64/kernel/cpuinfo.c
arch/arm64/kernel/efi.c
arch/arm64/kernel/fpsimd.c
arch/arm64/kernel/head.S
arch/arm64/kernel/perf_regs.c
arch/arm64/kernel/ptrace.c
arch/arm64/kernel/setup.c
arch/arm64/kvm/handle_exit.c
arch/arm64/kvm/hyp-init.S
arch/arm64/mm/init.c
arch/frv/include/asm/processor.h
arch/hexagon/mm/cache.c
arch/ia64/Kconfig
arch/ia64/include/asm/unistd.h
arch/ia64/include/uapi/asm/unistd.h
arch/ia64/kernel/entry.S
arch/m68k/Kconfig
arch/m68k/include/asm/unistd.h
arch/m68k/include/uapi/asm/unistd.h
arch/m68k/kernel/syscalltable.S
arch/microblaze/include/uapi/asm/unistd.h
arch/microblaze/kernel/syscall_table.S
arch/mips/Kconfig
arch/mips/alchemy/devboards/db1200.c
arch/mips/bcm47xx/setup.c
arch/mips/cavium-octeon/setup.c
arch/mips/include/asm/eva.h [new file with mode: 0644]
arch/mips/include/asm/gic.h
arch/mips/include/asm/irq.h
arch/mips/include/asm/mach-malta/kernel-entry-init.h
arch/mips/include/asm/mach-netlogic/topology.h
arch/mips/include/asm/pgtable.h
arch/mips/include/asm/syscall.h
arch/mips/kernel/cps-vec.S
arch/mips/kernel/perf_event_mipsxx.c
arch/mips/kernel/scall64-o32.S
arch/mips/loongson/loongson-3/cop2-ex.c
arch/mips/loongson/loongson-3/numa.c
arch/mips/mm/cache.c
arch/mips/mti-malta/malta-memory.c
arch/mips/net/bpf_jit.c
arch/mips/pmcs-msp71xx/msp_irq.c
arch/powerpc/Kconfig
arch/powerpc/kvm/book3s_64_mmu_hv.c
arch/powerpc/kvm/book3s_hv_builtin.c
arch/powerpc/net/bpf_jit_comp.c
arch/s390/Kconfig
arch/s390/include/asm/pgtable.h
arch/s390/include/uapi/asm/unistd.h
arch/s390/kernel/compat_wrapper.c
arch/s390/kernel/ipl.c
arch/s390/kernel/setup.c
arch/s390/kernel/syscalls.S
arch/s390/kvm/kvm-s390.c
arch/s390/mm/pgtable.c
arch/s390/net/bpf_jit_comp.c
arch/sh/Kconfig
arch/sh/mm/cache.c
arch/sparc/net/bpf_jit_comp.c
arch/tile/Kconfig
arch/tile/kernel/smp.c
arch/unicore32/kernel/signal.c
arch/x86/Kbuild
arch/x86/Kconfig
arch/x86/Makefile
arch/x86/include/asm/io_apic.h
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/pgtable.h
arch/x86/include/uapi/asm/msr-index.h
arch/x86/kernel/Makefile
arch/x86/kernel/apic/io_apic.c
arch/x86/kernel/crash.c
arch/x86/kernel/entry_32.S
arch/x86/kernel/irqinit.c
arch/x86/kernel/machine_kexec_64.c
arch/x86/kernel/time.c
arch/x86/kvm/emulate.c
arch/x86/mm/tlb.c
arch/x86/net/bpf_jit_comp.c
arch/x86/pci/intel_mid_pci.c
arch/x86/pci/irq.c
arch/x86/purgatory/Makefile
arch/xtensa/Kconfig
arch/xtensa/Makefile
arch/xtensa/boot/dts/kc705.dts
arch/xtensa/configs/common_defconfig
arch/xtensa/configs/iss_defconfig
arch/xtensa/configs/s6105_defconfig
arch/xtensa/include/asm/cacheflush.h
arch/xtensa/include/asm/fixmap.h
arch/xtensa/include/asm/highmem.h
arch/xtensa/include/asm/page.h
arch/xtensa/include/asm/pgtable.h
arch/xtensa/include/asm/uaccess.h
arch/xtensa/include/uapi/asm/ioctls.h
arch/xtensa/include/uapi/asm/unistd.h
arch/xtensa/kernel/align.S
arch/xtensa/kernel/entry.S
arch/xtensa/kernel/pci-dma.c
arch/xtensa/kernel/smp.c
arch/xtensa/kernel/traps.c
arch/xtensa/kernel/vectors.S
arch/xtensa/kernel/vmlinux.lds.S
arch/xtensa/mm/cache.c
arch/xtensa/mm/highmem.c
arch/xtensa/mm/misc.S
arch/xtensa/mm/mmu.c
block/bio-integrity.c
block/blk-core.c
block/blk-mq.c
block/cfq-iosched.c
block/scsi_ioctl.c
crypto/asymmetric_keys/public_key.c
crypto/asymmetric_keys/verify_pefile.c
drivers/acpi/acpi_lpss.c
drivers/acpi/acpica/nsprepkg.c
drivers/acpi/ec.c
drivers/acpi/pci_irq.c
drivers/acpi/processor_idle.c
drivers/acpi/scan.c
drivers/acpi/video.c
drivers/ata/ahci.c
drivers/ata/ahci_tegra.c
drivers/ata/ahci_xgene.c
drivers/ata/ata_piix.c
drivers/ata/libata-core.c
drivers/ata/pata_jmicron.c
drivers/ata/pata_samsung_cf.c
drivers/ata/pata_scc.c
drivers/base/regmap/internal.h
drivers/base/regmap/regcache-rbtree.c
drivers/base/regmap/regcache.c
drivers/base/regmap/regmap-debugfs.c
drivers/base/regmap/regmap.c
drivers/bcma/driver_mips.c
drivers/bcma/host_pci.c
drivers/bcma/host_soc.c
drivers/bcma/scan.c
drivers/block/brd.c
drivers/block/xsysace.c
drivers/block/zram/zram_drv.c
drivers/block/zram/zram_drv.h
drivers/bluetooth/ath3k.c
drivers/bluetooth/bluecard_cs.c
drivers/bluetooth/bt3c_cs.c
drivers/bluetooth/btuart_cs.c
drivers/bluetooth/btusb.c
drivers/bluetooth/dtl1_cs.c
drivers/bluetooth/hci_h5.c
drivers/bus/arm-ccn.c
drivers/char/hw_random/virtio-rng.c
drivers/cpufreq/intel_pstate.c
drivers/cpufreq/s5pv210-cpufreq.c
drivers/cpuidle/cpuidle-big_little.c
drivers/dma-buf/fence.c
drivers/edac/Kconfig
drivers/edac/edac_mc_sysfs.c
drivers/edac/sb_edac.c
drivers/firmware/efi/vars.c
drivers/gpio/devres.c
drivers/gpio/gpio-bt8xx.c
drivers/gpio/gpio-lynxpoint.c
drivers/gpio/gpio-zynq.c
drivers/gpio/gpiolib-of.c
drivers/gpu/drm/ast/ast_tables.h
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/intel_bios.c
drivers/gpu/drm/i915/intel_crt.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_panel.c
drivers/gpu/drm/i915/intel_tv.c
drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
drivers/gpu/drm/msm/msm_drv.c
drivers/gpu/drm/msm/msm_fbdev.c
drivers/gpu/drm/msm/msm_iommu.c
drivers/gpu/drm/nouveau/core/core/client.c
drivers/gpu/drm/nouveau/core/core/parent.c
drivers/gpu/drm/nouveau/core/engine/device/nve0.c
drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c
drivers/gpu/drm/nouveau/core/include/core/client.h
drivers/gpu/drm/nouveau/core/subdev/bar/base.c
drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c
drivers/gpu/drm/nouveau/core/subdev/ltc/gf100.c
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nouveau_display.c
drivers/gpu/drm/nouveau/nouveau_fbcon.c
drivers/gpu/drm/nouveau/nouveau_platform.c
drivers/gpu/drm/nouveau/nvif/class.h
drivers/gpu/drm/nouveau/nvif/notify.c
drivers/gpu/drm/nouveau/nvif/object.c
drivers/gpu/drm/radeon/Makefile
drivers/gpu/drm/radeon/ci_dpm.c
drivers/gpu/drm/radeon/cik.c
drivers/gpu/drm/radeon/cik_sdma.c
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/evergreen_dma.c
drivers/gpu/drm/radeon/kv_dpm.c
drivers/gpu/drm/radeon/ni.c
drivers/gpu/drm/radeon/r100.c
drivers/gpu/drm/radeon/r200.c
drivers/gpu/drm/radeon/r300.c
drivers/gpu/drm/radeon/r420.c
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/r600_dma.c
drivers/gpu/drm/radeon/r600d.h
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_cs.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/radeon_ib.c
drivers/gpu/drm/radeon/radeon_pm.c
drivers/gpu/drm/radeon/radeon_ring.c
drivers/gpu/drm/radeon/radeon_semaphore.c
drivers/gpu/drm/radeon/radeon_test.c
drivers/gpu/drm/radeon/radeon_uvd.c
drivers/gpu/drm/radeon/radeon_vce.c
drivers/gpu/drm/radeon/radeon_vm.c
drivers/gpu/drm/radeon/rv515.c
drivers/gpu/drm/radeon/rv770.c
drivers/gpu/drm/radeon/rv770_dma.c
drivers/gpu/drm/radeon/si.c
drivers/gpu/drm/radeon/si_dma.c
drivers/gpu/drm/radeon/trinity_dpm.c
drivers/gpu/drm/radeon/uvd_v1_0.c
drivers/gpu/drm/sti/Kconfig
drivers/gpu/drm/sti/sti_drm_drv.c
drivers/gpu/drm/sti/sti_hda.c
drivers/gpu/drm/sti/sti_hdmi.c
drivers/gpu/drm/sti/sti_tvout.c
drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
drivers/hid/hid-cherry.c
drivers/hid/hid-huion.c
drivers/hid/hid-kye.c
drivers/hid/hid-lg.c
drivers/hid/hid-lg4ff.c
drivers/hid/hid-logitech-dj.c
drivers/hid/hid-logitech-dj.h
drivers/hid/hid-magicmouse.c
drivers/hid/hid-monterey.c
drivers/hid/hid-petalynx.c
drivers/hid/hid-picolcd_core.c
drivers/hid/hid-rmi.c
drivers/hid/hid-sensor-hub.c
drivers/hid/hid-sunplus.c
drivers/hid/wacom_sys.c
drivers/hwmon/ds1621.c
drivers/i2c/Kconfig
drivers/i2c/Makefile
drivers/i2c/busses/i2c-at91.c
drivers/i2c/busses/i2c-i801.c
drivers/i2c/busses/i2c-mv64xxx.c
drivers/i2c/busses/i2c-rcar.c
drivers/i2c/busses/i2c-rk3x.c
drivers/i2c/i2c-acpi.c
drivers/idle/intel_idle.c
drivers/infiniband/hw/mlx4/main.c
drivers/infiniband/hw/mlx4/qp.c
drivers/input/input-mt.c
drivers/input/joystick/analog.c
drivers/input/joystick/xpad.c
drivers/input/keyboard/cap1106.c
drivers/input/mouse/alps.c
drivers/input/mouse/elantech.c
drivers/input/mouse/elantech.h
drivers/input/mouse/synaptics.c
drivers/input/serio/i8042-sparcio.h
drivers/input/touchscreen/atmel_mxt_ts.c
drivers/input/touchscreen/edt-ft5x06.c
drivers/iommu/amd_iommu.c
drivers/iommu/intel-iommu.c
drivers/iommu/iommu.c
drivers/isdn/gigaset/bas-gigaset.c
drivers/isdn/gigaset/usb-gigaset.c
drivers/isdn/hardware/eicon/xdi_msg.h
drivers/isdn/mISDN/dsp_cmx.c
drivers/leds/led-class.c
drivers/leds/led-core.c
drivers/md/dm-crypt.c
drivers/md/raid10.c
drivers/md/raid5.c
drivers/mfd/ab8500-core.c
drivers/mfd/htc-i2cpld.c
drivers/mfd/omap-usb-host.c
drivers/mfd/twl4030-power.c
drivers/misc/mei/client.c
drivers/misc/mei/nfc.c
drivers/mtd/chips/cfi_cmdset_0002.c
drivers/mtd/nand/omap2.c
drivers/net/bonding/bond_3ad.c
drivers/net/bonding/bond_alb.c
drivers/net/bonding/bond_main.c
drivers/net/bonding/bond_netlink.c
drivers/net/bonding/bond_options.c
drivers/net/bonding/bond_procfs.c
drivers/net/bonding/bond_sysfs.c
drivers/net/bonding/bonding.h
drivers/net/can/Kconfig
drivers/net/can/Makefile
drivers/net/can/c_can/Makefile
drivers/net/can/c_can/c_can_platform.c
drivers/net/can/cc770/Makefile
drivers/net/can/dev.c
drivers/net/can/flexcan.c
drivers/net/can/m_can/Kconfig [new file with mode: 0644]
drivers/net/can/m_can/Makefile [new file with mode: 0644]
drivers/net/can/m_can/m_can.c [new file with mode: 0644]
drivers/net/can/mscan/Makefile
drivers/net/can/rcar_can.c
drivers/net/can/sja1000/Makefile
drivers/net/can/sja1000/sja1000.c
drivers/net/can/softing/Makefile
drivers/net/can/spi/Makefile
drivers/net/can/spi/mcp251x.c
drivers/net/can/usb/Makefile
drivers/net/dsa/Kconfig
drivers/net/dsa/Makefile
drivers/net/dsa/bcm_sf2.c [new file with mode: 0644]
drivers/net/dsa/bcm_sf2.h [new file with mode: 0644]
drivers/net/dsa/bcm_sf2_regs.h [new file with mode: 0644]
drivers/net/ethernet/3com/3c509.c
drivers/net/ethernet/3com/3c515.c
drivers/net/ethernet/3com/3c59x.c
drivers/net/ethernet/aeroflex/greth.c
drivers/net/ethernet/aeroflex/greth.h
drivers/net/ethernet/amd/xgbe/xgbe-common.h
drivers/net/ethernet/amd/xgbe/xgbe-dcb.c
drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c
drivers/net/ethernet/amd/xgbe/xgbe-desc.c
drivers/net/ethernet/amd/xgbe/xgbe-dev.c
drivers/net/ethernet/amd/xgbe/xgbe-drv.c
drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c
drivers/net/ethernet/amd/xgbe/xgbe-main.c
drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
drivers/net/ethernet/amd/xgbe/xgbe-ptp.c
drivers/net/ethernet/amd/xgbe/xgbe.h
drivers/net/ethernet/apm/xgene/Kconfig
drivers/net/ethernet/apm/xgene/xgene_enet_main.c
drivers/net/ethernet/arc/Kconfig
drivers/net/ethernet/arc/Makefile
drivers/net/ethernet/arc/emac.h
drivers/net/ethernet/arc/emac_arc.c [new file with mode: 0644]
drivers/net/ethernet/arc/emac_main.c
drivers/net/ethernet/arc/emac_mdio.c
drivers/net/ethernet/arc/emac_rockchip.c [new file with mode: 0644]
drivers/net/ethernet/broadcom/Kconfig
drivers/net/ethernet/broadcom/b44.c
drivers/net/ethernet/broadcom/bcmsysport.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h
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_link.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h
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_stats.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
drivers/net/ethernet/broadcom/cnic.c
drivers/net/ethernet/broadcom/tg3.c
drivers/net/ethernet/broadcom/tg3.h
drivers/net/ethernet/brocade/bna/bnad.c
drivers/net/ethernet/calxeda/Kconfig
drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
drivers/net/ethernet/chelsio/cxgb4/sge.c
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
drivers/net/ethernet/chelsio/cxgb4vf/sge.c
drivers/net/ethernet/cisco/enic/enic.h
drivers/net/ethernet/cisco/enic/enic_ethtool.c
drivers/net/ethernet/cisco/enic/enic_main.c
drivers/net/ethernet/cisco/enic/vnic_dev.c
drivers/net/ethernet/dec/tulip/dmfe.c
drivers/net/ethernet/ec_bhf.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/freescale/fec.h
drivers/net/ethernet/freescale/fec_main.c
drivers/net/ethernet/freescale/fec_ptp.c
drivers/net/ethernet/hp/hp100.c
drivers/net/ethernet/ibm/ehea/ehea_main.c
drivers/net/ethernet/ibm/ibmveth.c
drivers/net/ethernet/intel/e1000/e1000_ethtool.c
drivers/net/ethernet/intel/e1000/e1000_main.c
drivers/net/ethernet/intel/e1000e/netdev.c
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_debugfs.c
drivers/net/ethernet/intel/i40e/i40e_ethtool.c
drivers/net/ethernet/intel/i40e/i40e_main.c
drivers/net/ethernet/intel/i40e/i40e_prototype.h
drivers/net/ethernet/intel/i40e/i40e_ptp.c
drivers/net/ethernet/intel/i40e/i40e_txrx.c
drivers/net/ethernet/intel/i40e/i40e_txrx.h
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
drivers/net/ethernet/intel/i40evf/i40e_adminq.c
drivers/net/ethernet/intel/i40evf/i40e_common.c
drivers/net/ethernet/intel/i40evf/i40e_prototype.h
drivers/net/ethernet/intel/i40evf/i40e_txrx.c
drivers/net/ethernet/intel/i40evf/i40e_txrx.h
drivers/net/ethernet/intel/i40evf/i40evf_main.c
drivers/net/ethernet/intel/igb/e1000_82575.c
drivers/net/ethernet/intel/igb/e1000_82575.h
drivers/net/ethernet/intel/igb/igb_ethtool.c
drivers/net/ethernet/intel/igb/igb_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
drivers/net/ethernet/intel/ixgbevf/vf.c
drivers/net/ethernet/marvell/mvneta.c
drivers/net/ethernet/marvell/skge.c
drivers/net/ethernet/marvell/sky2.c
drivers/net/ethernet/mellanox/mlx4/en_netdev.c
drivers/net/ethernet/mellanox/mlx4/en_rx.c
drivers/net/ethernet/mellanox/mlx4/en_tx.c
drivers/net/ethernet/mellanox/mlx4/mcg.c
drivers/net/ethernet/moxa/moxart_ether.c
drivers/net/ethernet/nvidia/forcedeth.c
drivers/net/ethernet/nxp/lpc_eth.c
drivers/net/ethernet/packetengines/yellowfin.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_hw.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
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_sysfs.c
drivers/net/ethernet/qlogic/qlge/qlge_main.c
drivers/net/ethernet/realtek/r8169.c
drivers/net/ethernet/renesas/Kconfig
drivers/net/ethernet/sfc/tx.c
drivers/net/ethernet/stmicro/stmmac/chain_mode.c
drivers/net/ethernet/stmicro/stmmac/common.h
drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
drivers/net/ethernet/stmicro/stmmac/mmc.h
drivers/net/ethernet/stmicro/stmmac/mmc_core.c
drivers/net/ethernet/stmicro/stmmac/ring_mode.c
drivers/net/ethernet/stmicro/stmmac/stmmac.h
drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
drivers/net/ethernet/sun/cassini.c
drivers/net/ethernet/sun/niu.c
drivers/net/ethernet/sun/sungem.c
drivers/net/ethernet/sun/sunvnet.c
drivers/net/ethernet/ti/cpmac.c
drivers/net/ethernet/ti/cpsw-phy-sel.c
drivers/net/ethernet/ti/cpsw.c
drivers/net/ethernet/ti/davinci_emac.c
drivers/net/ethernet/ti/davinci_mdio.c
drivers/net/ethernet/tile/tilepro.c
drivers/net/fddi/skfp/h/skfbi.h
drivers/net/hyperv/hyperv_net.h
drivers/net/hyperv/netvsc.c
drivers/net/irda/vlsi_ir.c
drivers/net/macvlan.c
drivers/net/phy/Kconfig
drivers/net/phy/Makefile
drivers/net/phy/amd-xgbe-phy.c
drivers/net/phy/bcm7xxx.c
drivers/net/phy/broadcom.c
drivers/net/phy/dp83640.c
drivers/net/phy/fixed.c
drivers/net/phy/mdio-bcm-unimac.c [new file with mode: 0644]
drivers/net/phy/mdio_bus.c
drivers/net/phy/phy.c
drivers/net/phy/phy_device.c
drivers/net/phy/smsc.c
drivers/net/sungem_phy.c
drivers/net/team/team.c
drivers/net/usb/r8152.c
drivers/net/virtio_net.c
drivers/net/vmxnet3/vmxnet3_drv.c
drivers/net/vmxnet3/vmxnet3_int.h
drivers/net/vxlan.c
drivers/net/wan/dlci.c
drivers/net/wireless/at76c50x-usb.c
drivers/net/wireless/ath/ath.h
drivers/net/wireless/ath/ath10k/Kconfig
drivers/net/wireless/ath/ath10k/Makefile
drivers/net/wireless/ath/ath10k/bmi.c
drivers/net/wireless/ath/ath10k/ce.c
drivers/net/wireless/ath/ath10k/ce.h
drivers/net/wireless/ath/ath10k/core.c
drivers/net/wireless/ath/ath10k/core.h
drivers/net/wireless/ath/ath10k/debug.c
drivers/net/wireless/ath/ath10k/debug.h
drivers/net/wireless/ath/ath10k/htc.c
drivers/net/wireless/ath/ath10k/htc.h
drivers/net/wireless/ath/ath10k/htt.c
drivers/net/wireless/ath/ath10k/htt_rx.c
drivers/net/wireless/ath/ath10k/htt_tx.c
drivers/net/wireless/ath/ath10k/hw.h
drivers/net/wireless/ath/ath10k/mac.c
drivers/net/wireless/ath/ath10k/mac.h
drivers/net/wireless/ath/ath10k/pci.c
drivers/net/wireless/ath/ath10k/pci.h
drivers/net/wireless/ath/ath10k/spectral.c [new file with mode: 0644]
drivers/net/wireless/ath/ath10k/spectral.h [new file with mode: 0644]
drivers/net/wireless/ath/ath10k/txrx.c
drivers/net/wireless/ath/ath10k/wmi.c
drivers/net/wireless/ath/ath10k/wmi.h
drivers/net/wireless/ath/ath5k/attach.c
drivers/net/wireless/ath/ath5k/base.c
drivers/net/wireless/ath/ath5k/debug.c
drivers/net/wireless/ath/ath5k/led.c
drivers/net/wireless/ath/ath6kl/cfg80211.c
drivers/net/wireless/ath/ath6kl/init.c
drivers/net/wireless/ath/ath6kl/main.c
drivers/net/wireless/ath/ath6kl/sdio.c
drivers/net/wireless/ath/ath6kl/usb.c
drivers/net/wireless/ath/ath6kl/wmi.c
drivers/net/wireless/ath/ath9k/Kconfig
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/beacon.c
drivers/net/wireless/ath/ath9k/channel.c
drivers/net/wireless/ath/ath9k/htc_drv_init.c
drivers/net/wireless/ath/ath9k/init.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/ath9k/spectral.c
drivers/net/wireless/ath/ath9k/spectral.h
drivers/net/wireless/ath/ath9k/wow.c
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/carl9170/main.c
drivers/net/wireless/ath/carl9170/tx.c
drivers/net/wireless/ath/spectral_common.h [new file with mode: 0644]
drivers/net/wireless/ath/wil6210/cfg80211.c
drivers/net/wireless/ath/wil6210/debugfs.c
drivers/net/wireless/ath/wil6210/interrupt.c
drivers/net/wireless/ath/wil6210/main.c
drivers/net/wireless/ath/wil6210/netdev.c
drivers/net/wireless/ath/wil6210/pcie_bus.c
drivers/net/wireless/ath/wil6210/rx_reorder.c
drivers/net/wireless/ath/wil6210/txrx.c
drivers/net/wireless/ath/wil6210/txrx.h
drivers/net/wireless/ath/wil6210/wil6210.h
drivers/net/wireless/ath/wil6210/wmi.c
drivers/net/wireless/ath/wil6210/wmi.h
drivers/net/wireless/atmel_cs.c
drivers/net/wireless/b43/Makefile
drivers/net/wireless/b43/b43.h
drivers/net/wireless/b43/bus.c
drivers/net/wireless/b43/bus.h
drivers/net/wireless/b43/main.c
drivers/net/wireless/b43/phy_a.c
drivers/net/wireless/b43/phy_common.c
drivers/net/wireless/b43/phy_g.c
drivers/net/wireless/b43/phy_ht.c
drivers/net/wireless/b43/phy_lcn.c
drivers/net/wireless/b43/phy_lp.c
drivers/net/wireless/b43/phy_n.c
drivers/net/wireless/b43/phy_n.h
drivers/net/wireless/b43/ppr.c [new file with mode: 0644]
drivers/net/wireless/b43/ppr.h [new file with mode: 0644]
drivers/net/wireless/b43/tables_nphy.c
drivers/net/wireless/b43/tables_nphy.h
drivers/net/wireless/brcm80211/brcmfmac/p2p.c
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
drivers/net/wireless/cw1200/cw1200_spi.c
drivers/net/wireless/ipw2x00/ipw2200.c
drivers/net/wireless/iwlwifi/Kconfig
drivers/net/wireless/iwlwifi/dvm/rxon.c
drivers/net/wireless/iwlwifi/dvm/tx.c
drivers/net/wireless/iwlwifi/iwl-7000.c
drivers/net/wireless/iwlwifi/iwl-8000.c
drivers/net/wireless/iwlwifi/iwl-csr.h
drivers/net/wireless/iwlwifi/iwl-debug.h
drivers/net/wireless/iwlwifi/iwl-devtrace.c
drivers/net/wireless/iwlwifi/iwl-drv.c
drivers/net/wireless/iwlwifi/iwl-drv.h
drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
drivers/net/wireless/iwlwifi/iwl-fw-file.h
drivers/net/wireless/iwlwifi/iwl-fw.h
drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
drivers/net/wireless/iwlwifi/iwl-op-mode.h
drivers/net/wireless/iwlwifi/iwl-prph.h
drivers/net/wireless/iwlwifi/iwl-scd.h [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-trans.h
drivers/net/wireless/iwlwifi/mvm/coex.c
drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
drivers/net/wireless/iwlwifi/mvm/constants.h
drivers/net/wireless/iwlwifi/mvm/d3.c
drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
drivers/net/wireless/iwlwifi/mvm/debugfs.c
drivers/net/wireless/iwlwifi/mvm/debugfs.h
drivers/net/wireless/iwlwifi/mvm/fw-api-coex.h
drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h
drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h
drivers/net/wireless/iwlwifi/mvm/fw-api.h
drivers/net/wireless/iwlwifi/mvm/fw.c
drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/mvm.h
drivers/net/wireless/iwlwifi/mvm/nvm.c
drivers/net/wireless/iwlwifi/mvm/offloading.c
drivers/net/wireless/iwlwifi/mvm/ops.c
drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
drivers/net/wireless/iwlwifi/mvm/power.c
drivers/net/wireless/iwlwifi/mvm/quota.c
drivers/net/wireless/iwlwifi/mvm/rs.c
drivers/net/wireless/iwlwifi/mvm/rx.c
drivers/net/wireless/iwlwifi/mvm/scan.c
drivers/net/wireless/iwlwifi/mvm/sf.c
drivers/net/wireless/iwlwifi/mvm/sta.c
drivers/net/wireless/iwlwifi/mvm/sta.h
drivers/net/wireless/iwlwifi/mvm/testmode.h
drivers/net/wireless/iwlwifi/mvm/time-event.c
drivers/net/wireless/iwlwifi/mvm/time-event.h
drivers/net/wireless/iwlwifi/mvm/tt.c
drivers/net/wireless/iwlwifi/mvm/tx.c
drivers/net/wireless/iwlwifi/mvm/utils.c
drivers/net/wireless/iwlwifi/pcie/drv.c
drivers/net/wireless/iwlwifi/pcie/internal.h
drivers/net/wireless/iwlwifi/pcie/rx.c
drivers/net/wireless/iwlwifi/pcie/trans.c
drivers/net/wireless/iwlwifi/pcie/tx.c
drivers/net/wireless/libertas/cfg.c
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/mwifiex/cmdevt.c
drivers/net/wireless/mwifiex/fw.h
drivers/net/wireless/mwifiex/init.c
drivers/net/wireless/mwifiex/main.h
drivers/net/wireless/mwifiex/scan.c
drivers/net/wireless/mwifiex/sta_cmd.c
drivers/net/wireless/mwifiex/sta_cmdresp.c
drivers/net/wireless/mwifiex/sta_ioctl.c
drivers/net/wireless/mwifiex/usb.c
drivers/net/wireless/mwifiex/util.c
drivers/net/wireless/orinoco/orinoco_usb.c
drivers/net/wireless/orinoco/scan.c
drivers/net/wireless/ray_cs.h
drivers/net/wireless/rayctl.h
drivers/net/wireless/rndis_wlan.c
drivers/net/wireless/rt2x00/rt2800.h
drivers/net/wireless/rt2x00/rt2800lib.c
drivers/net/wireless/rtlwifi/btcoexist/halbtcoutsrc.c
drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
drivers/net/wireless/ti/wl1251/spi.c
drivers/net/wireless/ti/wlcore/debug.h
drivers/net/wireless/ti/wlcore/spi.c
drivers/net/xen-netback/interface.c
drivers/of/fdt.c
drivers/of/irq.c
drivers/of/selftest.c
drivers/pci/host/Kconfig
drivers/pci/host/Makefile
drivers/pci/host/pci-dra7xx.c [new file with mode: 0644]
drivers/pci/host/pci-tegra.c
drivers/pci/host/pcie-designware.c
drivers/pci/host/pcie-designware.h
drivers/pinctrl/nomadik/pinctrl-abx500.c
drivers/pinctrl/pinctrl-at91.c
drivers/pinctrl/pinctrl-rockchip.c
drivers/pinctrl/pinctrl-tegra-xusb.c
drivers/pinctrl/samsung/pinctrl-exynos.c
drivers/pinctrl/samsung/pinctrl-samsung.h
drivers/pinctrl/sh-pfc/pfc-r8a7791.c
drivers/platform/x86/Kconfig
drivers/platform/x86/Makefile
drivers/platform/x86/acer-wmi.c
drivers/platform/x86/alienware-wmi.c
drivers/platform/x86/asus-nb-wmi.c
drivers/platform/x86/asus-wmi.c
drivers/platform/x86/compal-laptop.c
drivers/platform/x86/dell-laptop.c
drivers/platform/x86/eeepc-laptop.c
drivers/platform/x86/eeepc-wmi.c
drivers/platform/x86/fujitsu-laptop.c
drivers/platform/x86/fujitsu-tablet.c
drivers/platform/x86/hp-wmi.c
drivers/platform/x86/hp_accel.c
drivers/platform/x86/ideapad-laptop.c
drivers/platform/x86/intel_ips.c
drivers/platform/x86/sony-laptop.c
drivers/platform/x86/thinkpad_acpi.c
drivers/platform/x86/toshiba_acpi.c
drivers/platform/x86/toshiba_haps.c [new file with mode: 0644]
drivers/platform/x86/wmi.c
drivers/powercap/intel_rapl.c
drivers/pwm/core.c
drivers/rtc/rtc-s5m.c
drivers/s390/char/con3215.c
drivers/s390/char/sclp_tty.c
drivers/s390/net/qeth_core.h
drivers/s390/net/qeth_core_main.c
drivers/s390/net/qeth_l2_sys.c
drivers/scsi/libiscsi.c
drivers/scsi/pm8001/pm8001_ctl.c
drivers/scsi/pm8001/pm8001_hwi.c
drivers/scsi/pm8001/pm8001_init.c
drivers/scsi/qla4xxx/ql4_init.c
drivers/scsi/qla4xxx/ql4_mbx.c
drivers/scsi/qla4xxx/ql4_nx.c
drivers/scsi/qla4xxx/ql4_os.c
drivers/scsi/scsi.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_transport_iscsi.c
drivers/scsi/u14-34f.c
drivers/sh/Makefile
drivers/sh/intc/Kconfig
drivers/spi/spi-au1550.c
drivers/spi/spi-davinci.c
drivers/spi/spi-dw-pci.c
drivers/spi/spi-dw.c
drivers/spi/spi-omap2-mcspi.c
drivers/spi/spi-pxa2xx.c
drivers/spi/spi-rockchip.c
drivers/spi/spi-rspi.c
drivers/spi/spi-sh-msiof.c
drivers/spi/spi.c
drivers/ssb/b43_pci_bridge.c
drivers/staging/Kconfig
drivers/staging/Makefile
drivers/staging/android/logger.c
drivers/staging/et131x/et131x.c
drivers/staging/lustre/lustre/libcfs/workitem.c
drivers/staging/lustre/lustre/obdclass/class_obd.c
drivers/staging/rtl8188eu/os_dep/usb_intf.c
drivers/staging/rtl8723au/core/rtw_mlme_ext.c
drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c
drivers/staging/usbip/Kconfig [deleted file]
drivers/staging/usbip/Makefile [deleted file]
drivers/staging/usbip/README [deleted file]
drivers/staging/usbip/stub.h [deleted file]
drivers/staging/usbip/stub_dev.c [deleted file]
drivers/staging/usbip/stub_main.c [deleted file]
drivers/staging/usbip/stub_rx.c [deleted file]
drivers/staging/usbip/stub_tx.c [deleted file]
drivers/staging/usbip/uapi/usbip.h [deleted file]
drivers/staging/usbip/usbip_common.c [deleted file]
drivers/staging/usbip/usbip_common.h [deleted file]
drivers/staging/usbip/usbip_event.c [deleted file]
drivers/staging/usbip/usbip_protocol.txt [deleted file]
drivers/staging/usbip/userspace/.gitignore [deleted file]
drivers/staging/usbip/userspace/AUTHORS [deleted file]
drivers/staging/usbip/userspace/COPYING [deleted file]
drivers/staging/usbip/userspace/INSTALL [deleted file]
drivers/staging/usbip/userspace/Makefile.am [deleted file]
drivers/staging/usbip/userspace/README [deleted file]
drivers/staging/usbip/userspace/autogen.sh [deleted file]
drivers/staging/usbip/userspace/cleanup.sh [deleted file]
drivers/staging/usbip/userspace/configure.ac [deleted file]
drivers/staging/usbip/userspace/doc/usbip.8 [deleted file]
drivers/staging/usbip/userspace/doc/usbipd.8 [deleted file]
drivers/staging/usbip/userspace/libsrc/Makefile.am [deleted file]
drivers/staging/usbip/userspace/libsrc/list.h [deleted file]
drivers/staging/usbip/userspace/libsrc/names.c [deleted file]
drivers/staging/usbip/userspace/libsrc/names.h [deleted file]
drivers/staging/usbip/userspace/libsrc/sysfs_utils.c [deleted file]
drivers/staging/usbip/userspace/libsrc/sysfs_utils.h [deleted file]
drivers/staging/usbip/userspace/libsrc/usbip_common.c [deleted file]
drivers/staging/usbip/userspace/libsrc/usbip_common.h [deleted file]
drivers/staging/usbip/userspace/libsrc/usbip_host_driver.c [deleted file]
drivers/staging/usbip/userspace/libsrc/usbip_host_driver.h [deleted file]
drivers/staging/usbip/userspace/libsrc/vhci_driver.c [deleted file]
drivers/staging/usbip/userspace/libsrc/vhci_driver.h [deleted file]
drivers/staging/usbip/userspace/src/Makefile.am [deleted file]
drivers/staging/usbip/userspace/src/usbip.c [deleted file]
drivers/staging/usbip/userspace/src/usbip.h [deleted file]
drivers/staging/usbip/userspace/src/usbip_attach.c [deleted file]
drivers/staging/usbip/userspace/src/usbip_bind.c [deleted file]
drivers/staging/usbip/userspace/src/usbip_detach.c [deleted file]
drivers/staging/usbip/userspace/src/usbip_list.c [deleted file]
drivers/staging/usbip/userspace/src/usbip_network.c [deleted file]
drivers/staging/usbip/userspace/src/usbip_network.h [deleted file]
drivers/staging/usbip/userspace/src/usbip_port.c [deleted file]
drivers/staging/usbip/userspace/src/usbip_unbind.c [deleted file]
drivers/staging/usbip/userspace/src/usbipd.c [deleted file]
drivers/staging/usbip/userspace/src/utils.c [deleted file]
drivers/staging/usbip/userspace/src/utils.h [deleted file]
drivers/staging/usbip/vhci.h [deleted file]
drivers/staging/usbip/vhci_hcd.c [deleted file]
drivers/staging/usbip/vhci_rx.c [deleted file]
drivers/staging/usbip/vhci_sysfs.c [deleted file]
drivers/staging/usbip/vhci_tx.c [deleted file]
drivers/staging/wlan-ng/cfg80211.c
drivers/thunderbolt/path.c
drivers/usb/Kconfig
drivers/usb/Makefile
drivers/usb/core/hub.c
drivers/usb/dwc2/gadget.c
drivers/usb/dwc3/dwc3-omap.c
drivers/usb/gadget/Makefile
drivers/usb/gadget/function/Makefile
drivers/usb/gadget/function/f_ncm.c
drivers/usb/gadget/function/u_ether.c
drivers/usb/gadget/function/uvc_video.c
drivers/usb/gadget/legacy/Makefile
drivers/usb/gadget/legacy/dbgp.c
drivers/usb/gadget/legacy/inode.c
drivers/usb/gadget/udc/Kconfig
drivers/usb/gadget/udc/atmel_usba_udc.c
drivers/usb/gadget/udc/fusb300_udc.c
drivers/usb/gadget/udc/pch_udc.c
drivers/usb/gadget/udc/r8a66597-udc.c
drivers/usb/host/ehci-hub.c
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.c
drivers/usb/misc/sisusbvga/sisusb.c
drivers/usb/musb/ux500_dma.c
drivers/usb/phy/phy-gpio-vbus-usb.c
drivers/usb/phy/phy-msm-usb.c
drivers/usb/phy/phy-samsung-usb.h
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/pl2303.c
drivers/usb/serial/pl2303.h
drivers/usb/serial/usb-serial.c
drivers/usb/serial/whiteheat.c
drivers/usb/serial/zte_ev.c
drivers/usb/storage/unusual_devs.h
drivers/usb/usbip/Kconfig [new file with mode: 0644]
drivers/usb/usbip/Makefile [new file with mode: 0644]
drivers/usb/usbip/README [new file with mode: 0644]
drivers/usb/usbip/stub.h [new file with mode: 0644]
drivers/usb/usbip/stub_dev.c [new file with mode: 0644]
drivers/usb/usbip/stub_main.c [new file with mode: 0644]
drivers/usb/usbip/stub_rx.c [new file with mode: 0644]
drivers/usb/usbip/stub_tx.c [new file with mode: 0644]
drivers/usb/usbip/usbip_common.c [new file with mode: 0644]
drivers/usb/usbip/usbip_common.h [new file with mode: 0644]
drivers/usb/usbip/usbip_event.c [new file with mode: 0644]
drivers/usb/usbip/usbip_protocol.txt [new file with mode: 0644]
drivers/usb/usbip/vhci.h [new file with mode: 0644]
drivers/usb/usbip/vhci_hcd.c [new file with mode: 0644]
drivers/usb/usbip/vhci_rx.c [new file with mode: 0644]
drivers/usb/usbip/vhci_sysfs.c [new file with mode: 0644]
drivers/usb/usbip/vhci_tx.c [new file with mode: 0644]
drivers/usb/wusbcore/wa-xfer.c
drivers/video/backlight/pwm_bl.c
drivers/video/fbdev/amba-clcd.c
drivers/video/fbdev/atmel_lcdfb.c
drivers/video/fbdev/chipsfb.c
drivers/video/fbdev/da8xx-fb.c
drivers/video/of_display_timing.c
fs/aio.c
fs/btrfs/async-thread.c
fs/btrfs/async-thread.h
fs/btrfs/backref.c
fs/btrfs/btrfs_inode.h
fs/btrfs/ctree.c
fs/btrfs/ctree.h
fs/btrfs/delayed-inode.c
fs/btrfs/disk-io.c
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/file-item.c
fs/btrfs/file.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/ordered-data.c
fs/btrfs/ordered-data.h
fs/btrfs/qgroup.c
fs/btrfs/qgroup.h
fs/btrfs/raid56.c
fs/btrfs/reada.c
fs/btrfs/scrub.c
fs/btrfs/super.c
fs/btrfs/sysfs.c
fs/btrfs/transaction.c
fs/btrfs/transaction.h
fs/btrfs/tree-log.c
fs/btrfs/ulist.h
fs/btrfs/volumes.c
fs/cifs/cifsfs.c
fs/cifs/cifsglob.h
fs/cifs/cifspdu.h
fs/cifs/file.c
fs/cifs/inode.c
fs/cifs/misc.c
fs/cifs/readdir.c
fs/cifs/smb1ops.c
fs/cifs/smb2maperror.c
fs/cifs/smb2misc.c
fs/cifs/smb2ops.c
fs/cifs/smb2pdu.c
fs/cifs/smb2pdu.h
fs/cifs/smbfsctl.h
fs/ext3/super.c
fs/ext4/ext4.h
fs/ext4/extents.c
fs/ext4/inode.c
fs/ext4/mballoc.c
fs/ext4/namei.c
fs/ext4/super.c
fs/f2fs/Kconfig
fs/f2fs/checkpoint.c
fs/f2fs/data.c
fs/f2fs/debug.c
fs/f2fs/dir.c
fs/f2fs/f2fs.h
fs/f2fs/file.c
fs/f2fs/gc.c
fs/f2fs/gc.h
fs/f2fs/hash.c
fs/f2fs/inline.c
fs/f2fs/namei.c
fs/f2fs/node.c
fs/f2fs/recovery.c
fs/f2fs/segment.c
fs/f2fs/segment.h
fs/f2fs/super.c
fs/f2fs/xattr.c
fs/isofs/inode.c
fs/isofs/isofs.h
fs/isofs/rock.c
fs/jbd2/commit.c
fs/jbd2/journal.c
fs/jbd2/recovery.c
fs/jbd2/revoke.c
fs/locks.c
fs/namespace.c
fs/nfs/nfs3acl.c
fs/nfs/nfs4proc.c
fs/nfs/pagelist.c
fs/nfs/write.c
fs/ocfs2/cluster/quorum.c
fs/ocfs2/cluster/tcp.c
fs/ocfs2/cluster/tcp.h
fs/ocfs2/ioctl.c
fs/pnode.c
fs/sync.c
fs/udf/namei.c
fs/ufs/inode.c
fs/ufs/namei.c
fs/xfs/libxfs/xfs_bmap.c
fs/xfs/xfs_aops.c
fs/xfs/xfs_bmap_util.c
fs/xfs/xfs_file.c
include/acpi/acpi_bus.h
include/drm/drm_pciids.h
include/linux/bcma/bcma_regs.h
include/linux/blk-mq.h
include/linux/brcmphy.h
include/linux/cycx_x25.h [deleted file]
include/linux/edac.h
include/linux/etherdevice.h
include/linux/ethtool.h
include/linux/f2fs_fs.h
include/linux/filter.h
include/linux/ftrace.h
include/linux/gpio/consumer.h
include/linux/i2c.h
include/linux/i82593.h [deleted file]
include/linux/ieee80211.h
include/linux/igmp.h
include/linux/input/mt.h
include/linux/jbd2.h
include/linux/leds.h
include/linux/mlx4/device.h
include/linux/mtd/nand.h
include/linux/netdevice.h
include/linux/netfilter.h
include/linux/nfs_page.h
include/linux/phonedev.h [deleted file]
include/linux/phy.h
include/linux/phy_fixed.h
include/linux/platform_data/mtd-nand-omap2.h
include/linux/pm_domain.h
include/linux/random.h
include/linux/regulator/driver.h
include/linux/regulator/machine.h
include/linux/rhashtable.h
include/linux/seqno-fence.h
include/linux/skbuff.h
include/linux/spi/spi.h
include/linux/tcp.h
include/linux/tick.h
include/linux/udp.h
include/net/bluetooth/hci_core.h
include/net/bluetooth/l2cap.h
include/net/cfg80211.h
include/net/codel.h
include/net/dsa.h
include/net/flow_keys.h
include/net/inetpeer.h
include/net/ip.h
include/net/ip6_checksum.h
include/net/ip_fib.h
include/net/ipv6.h
include/net/mac80211.h
include/net/netns/ieee802154_6lowpan.h
include/net/netns/ipv4.h
include/net/pkt_sched.h
include/net/regulatory.h
include/net/sctp/sctp.h
include/net/sock.h
include/net/tcp.h
include/net/udp.h
include/net/wimax.h
include/rxrpc/types.h [deleted file]
include/scsi/iscsi_if.h
include/sound/soc.h
include/trace/events/irq.h
include/uapi/asm-generic/unistd.h
include/uapi/drm/radeon_drm.h
include/uapi/linux/Kbuild
include/uapi/linux/bpf.h [new file with mode: 0644]
include/uapi/linux/ethtool.h
include/uapi/linux/if_ether.h
include/uapi/linux/if_link.h
include/uapi/linux/nl80211.h
include/uapi/linux/usbip.h [new file with mode: 0644]
include/uapi/linux/xattr.h
kernel/bpf/core.c
kernel/cgroup.c
kernel/compat.c
kernel/crash_dump.c
kernel/events/core.c
kernel/irq/chip.c
kernel/kexec.c
kernel/kprobes.c
kernel/module.c
kernel/power/power.h
kernel/power/suspend.c
kernel/power/suspend_test.c
kernel/rcu/tree.h
kernel/rcu/tree_plugin.h
kernel/resource.c
kernel/seccomp.c
kernel/time/tick-sched.c
kernel/time/timekeeping.c
kernel/trace/ftrace.c
kernel/trace/ring_buffer.c
lib/Kconfig.debug
lib/assoc_array.c
lib/random32.c
lib/rhashtable.c
lib/test_bpf.c
mm/hugetlb_cgroup.c
mm/memblock.c
mm/memcontrol.c
mm/memory.c
mm/percpu-vm.c
mm/percpu.c
mm/pgtable-generic.c
mm/zbud.c
mm/zpool.c
mm/zsmalloc.c
net/atm/clip.c
net/atm/common.c
net/atm/lec.c
net/atm/mpc.c
net/batman-adv/fragmentation.c
net/bluetooth/6lowpan.c
net/bluetooth/hci_conn.c
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/l2cap_core.c
net/bluetooth/l2cap_sock.c
net/bluetooth/mgmt.c
net/bluetooth/smp.c
net/bluetooth/smp.h
net/bridge/br_if.c
net/bridge/br_multicast.c
net/bridge/br_netlink.c
net/core/datagram.c
net/core/dev.c
net/core/dev_ioctl.c
net/core/ethtool.c
net/core/filter.c
net/core/flow_dissector.c
net/core/gen_estimator.c
net/core/gen_stats.c
net/core/net_namespace.c
net/core/netpoll.c
net/core/pktgen.c
net/core/rtnetlink.c
net/core/secure_seq.c
net/core/skbuff.c
net/core/sock.c
net/core/timestamping.c
net/decnet/af_decnet.c
net/decnet/dn_dev.c
net/decnet/dn_timer.c
net/dsa/Kconfig
net/dsa/Makefile
net/dsa/dsa.c
net/dsa/dsa_priv.h
net/dsa/slave.c
net/dsa/tag_brcm.c [new file with mode: 0644]
net/dsa/tag_dsa.c
net/dsa/tag_edsa.c
net/dsa/tag_trailer.c
net/ethernet/eth.c
net/ieee802154/6lowpan_rtnl.c
net/ieee802154/reassembly.c
net/ipv4/af_inet.c
net/ipv4/fib_frontend.c
net/ipv4/fib_semantics.c
net/ipv4/gre_demux.c
net/ipv4/gre_offload.c
net/ipv4/igmp.c
net/ipv4/inet_hashtables.c
net/ipv4/inetpeer.c
net/ipv4/ip_sockglue.c
net/ipv4/ipconfig.c
net/ipv4/netfilter/Kconfig
net/ipv4/netfilter/Makefile
net/ipv4/netfilter/ipt_CLUSTERIP.c
net/ipv4/ping.c
net/ipv4/route.c
net/ipv4/syncookies.c
net/ipv4/sysctl_net_ipv4.c
net/ipv4/tcp_bic.c
net/ipv4/tcp_cong.c
net/ipv4/tcp_cubic.c
net/ipv4/tcp_diag.c
net/ipv4/tcp_highspeed.c
net/ipv4/tcp_htcp.c
net/ipv4/tcp_hybla.c
net/ipv4/tcp_illinois.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_minisocks.c
net/ipv4/tcp_offload.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/ipv6/addrconf.c
net/ipv6/af_inet6.c
net/ipv6/ah6.c
net/ipv6/anycast.c
net/ipv6/datagram.c
net/ipv6/esp6.c
net/ipv6/exthdrs.c
net/ipv6/icmp.c
net/ipv6/inet6_connection_sock.c
net/ipv6/inet6_hashtables.c
net/ipv6/ip6_fib.c
net/ipv6/ip6_flowlabel.c
net/ipv6/ip6_icmp.c
net/ipv6/ip6_input.c
net/ipv6/ip6_offload.c
net/ipv6/ip6_output.c
net/ipv6/ip6_tunnel.c
net/ipv6/ip6mr.c
net/ipv6/ipcomp6.c
net/ipv6/ipv6_sockglue.c
net/ipv6/mcast.c
net/ipv6/mip6.c
net/ipv6/ndisc.c
net/ipv6/netfilter/Kconfig
net/ipv6/netfilter/Makefile
net/ipv6/output_core.c
net/ipv6/proc.c
net/ipv6/raw.c
net/ipv6/reassembly.c
net/ipv6/route.c
net/ipv6/sit.c
net/ipv6/syncookies.c
net/ipv6/sysctl_net_ipv6.c
net/ipv6/tcp_ipv6.c
net/ipv6/tcpv6_offload.c
net/ipv6/tunnel6.c
net/ipv6/udp.c
net/ipv6/udp_offload.c
net/ipv6/xfrm6_input.c
net/ipv6/xfrm6_output.c
net/ipv6/xfrm6_policy.c
net/ipv6/xfrm6_state.c
net/ipv6/xfrm6_tunnel.c
net/iucv/iucv.c
net/l2tp/l2tp_core.c
net/l2tp/l2tp_ppp.c
net/mac80211/cfg.c
net/mac80211/chan.c
net/mac80211/debugfs_sta.c
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/key.c
net/mac80211/mesh_pathtbl.c
net/mac80211/mesh_plink.c
net/mac80211/mlme.c
net/mac80211/rx.c
net/mac80211/scan.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h
net/mac80211/tdls.c
net/mac80211/tx.c
net/mac80211/wme.c
net/mac802154/rx.c
net/mac802154/tx.c
net/mac802154/wpan.c
net/netfilter/Kconfig
net/netfilter/Makefile
net/netfilter/core.c
net/netfilter/ipset/ip_set_core.c
net/netfilter/ipset/ip_set_hash_gen.h
net/netfilter/ipvs/ip_vs_core.c
net/netfilter/ipvs/ip_vs_xmit.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_expect.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_conntrack_standalone.c
net/netfilter/nf_nat_core.c
net/netfilter/xt_HMARK.c
net/netfilter/xt_cgroup.c
net/netfilter/xt_cluster.c
net/netfilter/xt_connbytes.c
net/netfilter/xt_hashlimit.c
net/netfilter/xt_set.c
net/openvswitch/actions.c
net/openvswitch/datapath.c
net/openvswitch/flow.c
net/openvswitch/vport.c
net/openvswitch/vport.h
net/packet/af_packet.c
net/packet/internal.h
net/rfkill/rfkill-gpio.c
net/rose/rose_link.c
net/rxrpc/ar-error.c
net/rxrpc/ar-input.c
net/sched/act_police.c
net/sched/sch_cbq.c
net/sched/sch_fq.c
net/sched/sch_fq_codel.c
net/sched/sch_generic.c
net/sched/sch_htb.c
net/sched/sch_sfq.c
net/sched/sch_tbf.c
net/sched/sch_teql.c
net/sctp/associola.c
net/sctp/input.c
net/sctp/protocol.c
net/sctp/socket.c
net/socket.c
net/tipc/Makefile
net/tipc/bcast.c
net/tipc/config.c
net/tipc/core.c
net/tipc/core.h
net/tipc/link.c
net/tipc/link.h
net/tipc/msg.c
net/tipc/msg.h
net/tipc/name_distr.c
net/tipc/name_distr.h
net/tipc/name_table.c
net/tipc/net.c
net/tipc/node.c
net/tipc/node.h
net/tipc/port.c [deleted file]
net/tipc/port.h [deleted file]
net/tipc/ref.c [deleted file]
net/tipc/ref.h [deleted file]
net/tipc/socket.c
net/tipc/socket.h
net/tipc/subscr.c
net/tipc/sysctl.c
net/wireless/core.c
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/scan.c
net/xfrm/xfrm_output.c
scripts/checkpatch.pl
scripts/kernel-doc
security/keys/key.c
security/tomoyo/realpath.c
sound/core/info.c
sound/core/pcm_misc.c
sound/firewire/amdtp.c
sound/firewire/amdtp.h
sound/firewire/dice.c
sound/oss/uart401.c
sound/oss/waveartist.c
sound/pci/ctxfi/ct20k1reg.h
sound/pci/hda/ca0132_regs.h
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_ca0132.c
sound/pci/hda/patch_cmedia.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/soc/codecs/arizona.c
sound/soc/codecs/cs4265.c
sound/soc/codecs/da732x.h
sound/soc/codecs/pcm512x.c
sound/soc/codecs/rt5640.c
sound/soc/codecs/rt5677.c
sound/soc/davinci/davinci-mcasp.c
sound/soc/fsl/Kconfig
sound/soc/fsl/fsl_esai.c
sound/soc/generic/simple-card.c
sound/soc/intel/sst-acpi.c
sound/soc/intel/sst-baytrail-ipc.c
sound/soc/intel/sst-baytrail-ipc.h
sound/soc/intel/sst-baytrail-pcm.c
sound/soc/omap/omap-twl4030.c
sound/soc/pxa/pxa-ssp.c
sound/soc/sh/rcar/gen.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/tegra/tegra_asoc_utils.h
sound/usb/quirks-table.h
tools/power/x86/turbostat/turbostat.c
tools/testing/selftests/ipc/Makefile
tools/testing/selftests/kcmp/Makefile
tools/testing/selftests/memfd/Makefile
tools/usb/usbip/.gitignore [new file with mode: 0644]
tools/usb/usbip/AUTHORS [new file with mode: 0644]
tools/usb/usbip/COPYING [new file with mode: 0644]
tools/usb/usbip/INSTALL [new file with mode: 0644]
tools/usb/usbip/Makefile.am [new file with mode: 0644]
tools/usb/usbip/README [new file with mode: 0644]
tools/usb/usbip/autogen.sh [new file with mode: 0755]
tools/usb/usbip/cleanup.sh [new file with mode: 0755]
tools/usb/usbip/configure.ac [new file with mode: 0644]
tools/usb/usbip/doc/usbip.8 [new file with mode: 0644]
tools/usb/usbip/doc/usbipd.8 [new file with mode: 0644]
tools/usb/usbip/libsrc/Makefile.am [new file with mode: 0644]
tools/usb/usbip/libsrc/list.h [new file with mode: 0644]
tools/usb/usbip/libsrc/names.c [new file with mode: 0644]
tools/usb/usbip/libsrc/names.h [new file with mode: 0644]
tools/usb/usbip/libsrc/sysfs_utils.c [new file with mode: 0644]
tools/usb/usbip/libsrc/sysfs_utils.h [new file with mode: 0644]
tools/usb/usbip/libsrc/usbip_common.c [new file with mode: 0644]
tools/usb/usbip/libsrc/usbip_common.h [new file with mode: 0644]
tools/usb/usbip/libsrc/usbip_host_driver.c [new file with mode: 0644]
tools/usb/usbip/libsrc/usbip_host_driver.h [new file with mode: 0644]
tools/usb/usbip/libsrc/vhci_driver.c [new file with mode: 0644]
tools/usb/usbip/libsrc/vhci_driver.h [new file with mode: 0644]
tools/usb/usbip/src/Makefile.am [new file with mode: 0644]
tools/usb/usbip/src/usbip.c [new file with mode: 0644]
tools/usb/usbip/src/usbip.h [new file with mode: 0644]
tools/usb/usbip/src/usbip_attach.c [new file with mode: 0644]
tools/usb/usbip/src/usbip_bind.c [new file with mode: 0644]
tools/usb/usbip/src/usbip_detach.c [new file with mode: 0644]
tools/usb/usbip/src/usbip_list.c [new file with mode: 0644]
tools/usb/usbip/src/usbip_network.c [new file with mode: 0644]
tools/usb/usbip/src/usbip_network.h [new file with mode: 0644]
tools/usb/usbip/src/usbip_port.c [new file with mode: 0644]
tools/usb/usbip/src/usbip_unbind.c [new file with mode: 0644]
tools/usb/usbip/src/usbipd.c [new file with mode: 0644]
tools/usb/usbip/src/utils.c [new file with mode: 0644]
tools/usb/usbip/src/utils.h [new file with mode: 0644]
virt/kvm/assigned-dev.c
virt/kvm/iommu.c

index 1d3756d3176ce58656999f8103a98e6256f9b2a5..bacefc5b222ec0dff365e83c63191859d5803a22 100644 (file)
@@ -315,7 +315,7 @@ char *date;</synopsis>
         <function>drm_dev_unregister()</function> followed by a call to
         <function>drm_dev_unref()</function>.
       </para>
-!Edrivers/gpu/drm/drm_stub.c
+!Edrivers/gpu/drm/drm_drv.c
     </sect2>
     <sect2>
       <title>Driver Load</title>
index 0a523c9a5ff4ec2fee6eefd5e5acef87944460a2..482c74947de02939eebfca089a344373707bf69d 100644 (file)
@@ -794,6 +794,7 @@ Greg Kroah-Hartman, "How to piss off a kernel subsystem maintainer".
   <http://www.kroah.com/log/linux/maintainer-03.html>
   <http://www.kroah.com/log/linux/maintainer-04.html>
   <http://www.kroah.com/log/linux/maintainer-05.html>
+  <http://www.kroah.com/log/linux/maintainer-06.html>
 
 NO!!!! No more huge patch bombs to linux-kernel@vger.kernel.org people!
   <https://lkml.org/lkml/2005/7/11/336>
index baef432e83690af95ed6e3b49c1636c90f8ba135..0ac23f2ed1040c2c9f820677fdf3f5092a7c1a6d 100644 (file)
@@ -15,6 +15,17 @@ Optional properties for main touchpad device:
     keycode generated by each GPIO. Linux keycodes are defined in
     <dt-bindings/input/input.h>.
 
+- linux,gpio-keymap: When enabled, the SPT_GPIOPWN_T19 object sends messages
+    on GPIO bit changes. An array of up to 8 entries can be provided
+    indicating the Linux keycode mapped to each bit of the status byte,
+    starting at the LSB. Linux keycodes are defined in
+    <dt-bindings/input/input.h>.
+
+    Note: the numbering of the GPIOs and the bit they start at varies between
+    maXTouch devices. You must either refer to the documentation, or
+    experiment to determine which bit corresponds to which input. Use
+    KEY_RESERVED for unused padding values.
+
 Example:
 
        touch@4b {
index 1486497a24c1d41c9d64208b4178a8cb2e2c28d1..ce6a1a0720285bd9be4549d478ea49b4b985ee31 100644 (file)
@@ -4,11 +4,13 @@ Specifying interrupt information for devices
 1) Interrupt client nodes
 -------------------------
 
-Nodes that describe devices which generate interrupts must contain an either an
-"interrupts" property or an "interrupts-extended" property. These properties
-contain a list of interrupt specifiers, one per output interrupt. The format of
-the interrupt specifier is determined by the interrupt controller to which the
-interrupts are routed; see section 2 below for details.
+Nodes that describe devices which generate interrupts must contain an
+"interrupts" property, an "interrupts-extended" property, or both. If both are
+present, the latter should take precedence; the former may be provided simply
+for compatibility with software that does not recognize the latter. These
+properties contain a list of interrupt specifiers, one per output interrupt. The
+format of the interrupt specifier is determined by the interrupt controller to
+which the interrupts are routed; see section 2 below for details.
 
   Example:
        interrupt-parent = <&intc1>;
diff --git a/Documentation/devicetree/bindings/mfd/tc3589x.txt b/Documentation/devicetree/bindings/mfd/tc3589x.txt
new file mode 100644 (file)
index 0000000..6fcedba
--- /dev/null
@@ -0,0 +1,107 @@
+* Toshiba TC3589x multi-purpose expander
+
+The Toshiba TC3589x series are I2C-based MFD devices which may expose the
+following built-in devices: gpio, keypad, rotator (vibrator), PWM (for
+e.g. LEDs or vibrators) The included models are:
+
+- TC35890
+- TC35892
+- TC35893
+- TC35894
+- TC35895
+- TC35896
+
+Required properties:
+ - compatible : must be "toshiba,tc35890", "toshiba,tc35892", "toshiba,tc35893",
+   "toshiba,tc35894", "toshiba,tc35895" or "toshiba,tc35896"
+ - reg : I2C address of the device
+ - interrupt-parent : specifies which IRQ controller we're connected to
+ - interrupts : the interrupt on the parent the controller is connected to
+ - interrupt-controller : marks the device node as an interrupt controller
+ - #interrupt-cells : should be <1>, the first cell is the IRQ offset on this
+   TC3589x interrupt controller.
+
+Optional nodes:
+
+- GPIO
+  This GPIO module inside the TC3589x has 24 (TC35890, TC35892) or 20
+  (other models) GPIO lines.
+ - compatible : must be "toshiba,tc3589x-gpio"
+ - interrupts : interrupt on the parent, which must be the tc3589x MFD device
+ - interrupt-controller : marks the device node as an interrupt controller
+ - #interrupt-cells : should be <2>, the first cell is the IRQ offset on this
+   TC3589x GPIO interrupt controller, the second cell is the interrupt flags
+   in accordance with <dt-bindings/interrupt-controller/irq.h>. The following
+   flags are valid:
+   - IRQ_TYPE_LEVEL_LOW
+   - IRQ_TYPE_LEVEL_HIGH
+   - IRQ_TYPE_EDGE_RISING
+   - IRQ_TYPE_EDGE_FALLING
+   - IRQ_TYPE_EDGE_BOTH
+ - gpio-controller : marks the device node as a GPIO controller
+ - #gpio-cells : should be <2>, the first cell is the GPIO offset on this
+   GPIO controller, the second cell is the flags.
+
+- Keypad
+  This keypad is the same on all variants, supporting up to 96 different
+  keys. The linux-specific properties are modeled on those already existing
+  in other input drivers.
+ - compatible : must be "toshiba,tc3589x-keypad"
+ - debounce-delay-ms : debounce interval in milliseconds
+ - keypad,num-rows : number of rows in the matrix, see
+   bindings/input/matrix-keymap.txt
+ - keypad,num-columns : number of columns in the matrix, see
+   bindings/input/matrix-keymap.txt
+ - linux,keymap: the definition can be found in
+   bindings/input/matrix-keymap.txt
+ - linux,no-autorepeat: do no enable autorepeat feature.
+ - linux,wakeup: use any event on keypad as wakeup event.
+
+Example:
+
+tc35893@44 {
+       compatible = "toshiba,tc35893";
+       reg = <0x44>;
+       interrupt-parent = <&gpio6>;
+       interrupts = <26 IRQ_TYPE_EDGE_RISING>;
+
+       interrupt-controller;
+       #interrupt-cells = <1>;
+
+       tc3589x_gpio {
+               compatible = "toshiba,tc3589x-gpio";
+               interrupts = <0>;
+
+               interrupt-controller;
+               #interrupt-cells = <2>;
+               gpio-controller;
+               #gpio-cells = <2>;
+       };
+       tc3589x_keypad {
+               compatible = "toshiba,tc3589x-keypad";
+               interrupts = <6>;
+               debounce-delay-ms = <4>;
+               keypad,num-columns = <8>;
+               keypad,num-rows = <8>;
+               linux,no-autorepeat;
+               linux,wakeup;
+               linux,keymap = <0x0301006b
+                               0x04010066
+                               0x06040072
+                               0x040200d7
+                               0x0303006a
+                               0x0205000e
+                               0x0607008b
+                               0x0500001c
+                               0x0403000b
+                               0x03040034
+                               0x05020067
+                               0x0305006c
+                               0x040500e7
+                               0x0005009e
+                               0x06020073
+                               0x01030039
+                               0x07060069
+                               0x050500d9>;
+       };
+};
index 65f4f7c43136a0507ddbb23a7dc511c94cc34cdb..ee654e95d8ad55c3b53259b9f087be596b6dc99a 100644 (file)
@@ -22,7 +22,7 @@ Optional properties:
                                width of 8 is assumed.
 
  - ti,nand-ecc-opt:            A string setting the ECC layout to use. One of:
-               "sw"            <deprecated> use "ham1" instead
+               "sw"            1-bit Hamming ecc code via software
                "hw"            <deprecated> use "ham1" instead
                "hw-romcode"    <deprecated> use "ham1" instead
                "ham1"          1-bit Hamming ecc code
diff --git a/Documentation/devicetree/bindings/net/broadcom-mdio-unimac.txt b/Documentation/devicetree/bindings/net/broadcom-mdio-unimac.txt
new file mode 100644 (file)
index 0000000..ab0bb42
--- /dev/null
@@ -0,0 +1,39 @@
+* Broadcom UniMAC MDIO bus controller
+
+Required properties:
+- compatible: should one from "brcm,genet-mdio-v1", "brcm,genet-mdio-v2",
+  "brcm,genet-mdio-v3", "brcm,genet-mdio-v4" or "brcm,unimac-mdio"
+- reg: address and length of the regsiter set for the device, first one is the
+  base register, and the second one is optional and for indirect accesses to
+  larger than 16-bits MDIO transactions
+- reg-names: name(s) of the register must be "mdio" and optional "mdio_indir_rw"
+- #size-cells: must be 1
+- #address-cells: must be 0
+
+Optional properties:
+- interrupts: must be one if the interrupt is shared with the Ethernet MAC or
+  Ethernet switch this MDIO block is integrated from, or must be two, if there
+  are two separate interrupts, first one must be "mdio done" and second must be
+  for "mdio error"
+- interrupt-names: must be "mdio_done_error" when there is a share interrupt fed
+  to this hardware block, or must be "mdio_done" for the first interrupt and
+  "mdio_error" for the second when there are separate interrupts
+
+Child nodes of this MDIO bus controller node are standard Ethernet PHY device
+nodes as described in Documentation/devicetree/bindings/net/phy.txt
+
+Example:
+
+mdio@403c0 {
+       compatible = "brcm,unimac-mdio";
+       reg = <0x403c0 0x8 0x40300 0x18>;
+       reg-names = "mdio", "mdio_indir_rw";
+       #size-cells = <1>;
+       #address-cells = <0>;
+
+       ...
+       phy@0 {
+               compatible = "ethernet-phy-ieee802.3-c22";
+               reg = <0>;
+       };
+};
diff --git a/Documentation/devicetree/bindings/net/broadcom-sf2.txt b/Documentation/devicetree/bindings/net/broadcom-sf2.txt
new file mode 100644 (file)
index 0000000..30d4875
--- /dev/null
@@ -0,0 +1,78 @@
+* Broadcom Starfighter 2 integrated swich
+
+Required properties:
+
+- compatible: should be "brcm,bcm7445-switch-v4.0"
+- reg: addresses and length of the register sets for the device, must be 6
+  pairs of register addresses and lengths
+- interrupts: interrupts for the devices, must be two interrupts
+- dsa,mii-bus: phandle to the MDIO bus controller, see dsa/dsa.txt
+- dsa,ethernet: phandle to the CPU network interface controller, see dsa/dsa.txt
+- #size-cells: must be 0
+- #address-cells: must be 2, see dsa/dsa.txt
+
+Subnodes:
+
+The integrated switch subnode should be specified according to the binding
+described in dsa/dsa.txt.
+
+Optional properties:
+
+- reg-names: litteral names for the device base register addresses, when present
+  must be: "core", "reg", "intrl2_0", "intrl2_1", "fcb", "acb"
+
+- interrupt-names: litternal names for the device interrupt lines, when present
+  must be: "switch_0" and "switch_1"
+
+- brcm,num-gphy: specify the maximum number of integrated gigabit PHYs in the
+  switch
+
+- brcm,num-rgmii-ports: specify the maximum number of RGMII interfaces supported
+  by the switch
+
+- brcm,fcb-pause-override: boolean property, if present indicates that the switch
+  supports Failover Control Block pause override capability
+
+- brcm,acb-packets-inflight: boolean property, if present indicates that the switch
+  Admission Control Block supports reporting the number of packets in-flight in a
+  switch queue
+
+Example:
+
+switch_top@f0b00000 {
+       compatible = "simple-bus";
+       #size-cells = <1>;
+       #address-cells = <1>;
+       ranges = <0 0xf0b00000 0x40804>;
+
+       ethernet_switch@0 {
+               compatible = "brcm,bcm7445-switch-v4.0";
+               #size-cells = <0>;
+               #address-cells = <2>;
+               reg = <0x0 0x40000
+                       0x40000 0x110
+                       0x40340 0x30
+                       0x40380 0x30
+                       0x40400 0x34
+                       0x40600 0x208>;
+               interrupts = <0 0x18 0
+                               0 0x19 0>;
+               brcm,num-gphy = <1>;
+               brcm,num-rgmii-ports = <2>;
+               brcm,fcb-pause-override;
+               brcm,acb-packets-inflight;
+
+               ...
+               switch@0 {
+                       reg = <0 0>;
+                       #size-cells = <0>;
+                       #address-cells <1>;
+
+                       port@0 {
+                               label = "gphy";
+                               reg = <0>;
+                       };
+                       ...
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/net/can/m_can.txt b/Documentation/devicetree/bindings/net/can/m_can.txt
new file mode 100644 (file)
index 0000000..9e33177
--- /dev/null
@@ -0,0 +1,67 @@
+Bosch MCAN controller Device Tree Bindings
+-------------------------------------------------
+
+Required properties:
+- compatible           : Should be "bosch,m_can" for M_CAN controllers
+- reg                  : physical base address and size of the M_CAN
+                         registers map and Message RAM
+- reg-names            : Should be "m_can" and "message_ram"
+- interrupts           : Should be the interrupt number of M_CAN interrupt
+                         line 0 and line 1, could be same if sharing
+                         the same interrupt.
+- interrupt-names      : Should contain "int0" and "int1"
+- clocks               : Clocks used by controller, should be host clock
+                         and CAN clock.
+- clock-names          : Should contain "hclk" and "cclk"
+- pinctrl-<n>          : Pinctrl states as described in bindings/pinctrl/pinctrl-bindings.txt
+- pinctrl-names        : Names corresponding to the numbered pinctrl states
+- bosch,mram-cfg       : Message RAM configuration data.
+                         Multiple M_CAN instances can share the same Message
+                         RAM and each element(e.g Rx FIFO or Tx Buffer and etc)
+                         number in Message RAM is also configurable,
+                         so this property is telling driver how the shared or
+                         private Message RAM are used by this M_CAN controller.
+
+                         The format should be as follows:
+                         <offset sidf_elems xidf_elems rxf0_elems rxf1_elems
+                          rxb_elems txe_elems txb_elems>
+                         The 'offset' is an address offset of the Message RAM
+                         where the following elements start from. This is
+                         usually set to 0x0 if you're using a private Message
+                         RAM. The remain cells are used to specify how many
+                         elements are used for each FIFO/Buffer.
+
+                         M_CAN includes the following elements according to user manual:
+                         11-bit Filter 0-128 elements / 0-128 words
+                         29-bit Filter 0-64 elements / 0-128 words
+                         Rx FIFO 0     0-64 elements / 0-1152 words
+                         Rx FIFO 1     0-64 elements / 0-1152 words
+                         Rx Buffers    0-64 elements / 0-1152 words
+                         Tx Event FIFO 0-32 elements / 0-64 words
+                         Tx Buffers    0-32 elements / 0-576 words
+
+                         Please refer to 2.4.1 Message RAM Configuration in
+                         Bosch M_CAN user manual for details.
+
+Example:
+SoC dtsi:
+m_can1: can@020e8000 {
+       compatible = "bosch,m_can";
+       reg = <0x020e8000 0x4000>, <0x02298000 0x4000>;
+       reg-names = "m_can", "message_ram";
+       interrupts = <0 114 0x04>,
+                    <0 114 0x04>;
+       interrupt-names = "int0", "int1";
+       clocks = <&clks IMX6SX_CLK_CANFD>,
+                <&clks IMX6SX_CLK_CANFD>;
+       clock-names = "hclk", "cclk";
+       bosch,mram-cfg = <0x0 0 0 32 0 0 0 1>;
+       status = "disabled";
+};
+
+Board dts:
+&m_can1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_m_can1>;
+       status = "enabled";
+};
diff --git a/Documentation/devicetree/bindings/net/can/rcar_can.txt b/Documentation/devicetree/bindings/net/can/rcar_can.txt
new file mode 100644 (file)
index 0000000..002d844
--- /dev/null
@@ -0,0 +1,43 @@
+Renesas R-Car CAN controller Device Tree Bindings
+-------------------------------------------------
+
+Required properties:
+- compatible: "renesas,can-r8a7778" if CAN controller is a part of R8A7778 SoC.
+             "renesas,can-r8a7779" if CAN controller is a part of R8A7779 SoC.
+             "renesas,can-r8a7790" if CAN controller is a part of R8A7790 SoC.
+             "renesas,can-r8a7791" if CAN controller is a part of R8A7791 SoC.
+- reg: physical base address and size of the R-Car CAN register map.
+- interrupts: interrupt specifier for the sole interrupt.
+- clocks: phandles and clock specifiers for 3 CAN clock inputs.
+- clock-names: 3 clock input name strings: "clkp1", "clkp2", "can_clk".
+- pinctrl-0: pin control group to be used for this controller.
+- pinctrl-names: must be "default".
+
+Optional properties:
+- renesas,can-clock-select: R-Car CAN Clock Source Select. Valid values are:
+                           <0x0> (default) : Peripheral clock (clkp1)
+                           <0x1> : Peripheral clock (clkp2)
+                           <0x3> : Externally input clock
+
+Example
+-------
+
+SoC common .dtsi file:
+
+       can0: can@e6e80000 {
+               compatible = "renesas,can-r8a7791";
+               reg = <0 0xe6e80000 0 0x1000>;
+               interrupts = <0 186 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&mstp9_clks R8A7791_CLK_RCAN0>,
+                        <&cpg_clocks R8A7791_CLK_RCAN>, <&can_clk>;
+               clock-names = "clkp1", "clkp2", "can_clk";
+               status = "disabled";
+       };
+
+Board specific .dts file:
+
+&can0 {
+       pinctrl-0 = <&can0_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+};
index 49f4f7ae3f5145921a6def4250cc39fabb4fdafa..a62c889aafcaf070774bc3e9bc93c96ba9ea1992 100644 (file)
@@ -39,6 +39,22 @@ Optionnal property:
                          This property is only used when switches are being
                          chained/cascaded together.
 
+- phy-handle           : Phandle to a PHY on an external MDIO bus, not the
+                         switch internal one. See
+                         Documentation/devicetree/bindings/net/ethernet.txt
+                         for details.
+
+- phy-mode             : String representing the connection to the designated
+                         PHY node specified by the 'phy-handle' property. See
+                         Documentation/devicetree/bindings/net/ethernet.txt
+                         for details.
+
+Optional subnodes:
+- fixed-link           : Fixed-link subnode describing a link to a non-MDIO
+                         managed entity. See
+                         Documentation/devicetree/bindings/net/fixed-link.txt
+                         for details.
+
 Example:
 
        dsa@0 {
@@ -58,6 +74,7 @@ Example:
                        port@0 {
                                reg = <0>;
                                label = "lan1";
+                               phy-handle = <&phy0>;
                        };
 
                        port@1 {
diff --git a/Documentation/devicetree/bindings/net/emac_rockchip.txt b/Documentation/devicetree/bindings/net/emac_rockchip.txt
new file mode 100644 (file)
index 0000000..8dc1c79
--- /dev/null
@@ -0,0 +1,50 @@
+* ARC EMAC 10/100 Ethernet platform driver for Rockchip Rk3066/RK3188 SoCs
+
+Required properties:
+- compatible: Should be "rockchip,rk3066-emac" or "rockchip,rk3188-emac"
+  according to the target SoC.
+- reg: Address and length of the register set for the device
+- interrupts: Should contain the EMAC interrupts
+- rockchip,grf: phandle to the syscon grf used to control speed and mode
+  for emac.
+- phy: see ethernet.txt file in the same directory.
+- phy-mode: see ethernet.txt file in the same directory.
+
+Optional properties:
+- phy-supply: phandle to a regulator if the PHY needs one
+
+Clock handling:
+- clocks: Must contain an entry for each entry in clock-names.
+- clock-names: Shall be "hclk" for the host clock needed to calculate and set
+  polling period of EMAC and "macref" for the reference clock needed to transfer
+  data to and from the phy.
+
+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.
+
+Examples:
+
+ethernet@10204000 {
+       compatible = "rockchip,rk3188-emac";
+       reg = <0xc0fc2000 0x3c>;
+       interrupts = <6>;
+       mac-address = [ 00 11 22 33 44 55 ];
+
+       clocks = <&cru HCLK_EMAC>, <&cru SCLK_MAC>;
+       clock-names = "hclk", "macref";
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&emac_xfer>, <&emac_mdio>, <&phy_int>;
+
+       rockchip,grf = <&grf>;
+
+       phy = <&phy0>;
+       phy-mode = "rmii";
+       phy-supply = <&vcc_rmii>;
+
+       #address-cells = <1>;
+       #size-cells = <0>;
+       phy0: ethernet-phy@0 {
+             reg = <1>;
+       };
+};
index 2a60cd3e8d5ddb7bdf3b2caad2bc414a3d8566e0..3a9d6795160654080ec4aaa114304b62d5f0754f 100644 (file)
@@ -12,6 +12,10 @@ Required properties:
  - altr,sysmgr-syscon : Should be the phandle to the system manager node that
    encompasses the glue register, the register offset, and the register shift.
 
+Optional properties:
+altr,emac-splitter: Should be the phandle to the emac splitter soft IP node if
+               DWMAC controller is connected emac splitter.
+
 Example:
 
 gmac0: ethernet@ff700000 {
index 9b03c57563a49d2145fb47c2a5086ff71506fe3f..e45ac3f926b164636b73e4280cf40ddfde314203 100644 (file)
@@ -39,6 +39,10 @@ Optional properties:
   further clocks may be specified in derived bindings.
 - clock-names: One name for each entry in the clocks property, the
   first one should be "stmmaceth".
+- clk_ptp_ref: this is the PTP reference clock; in case of the PTP is
+  available this clock is used for programming the Timestamp Addend Register.
+  If not passed then the system clock will be used and this is fine on some
+  platforms.
 
 Examples:
 
index d0d15ee42834089abfd2ffad2bad205b28e33d18..ed0d9b9fff2be5f5be5902554d0da70ed81591df 100644 (file)
@@ -2,6 +2,10 @@
 
 Required properties:
 - compatible: should contain "snps,dw-pcie" to identify the core.
+- reg: Should contain the configuration address space.
+- reg-names: Must be "config" for the PCIe configuration space.
+    (The old way of getting the configuration address space from "ranges"
+    is deprecated and should be avoided.)
 - #address-cells: set to <3>
 - #size-cells: set to <2>
 - device_type: set to "pci"
diff --git a/Documentation/devicetree/bindings/pci/ti-pci.txt b/Documentation/devicetree/bindings/pci/ti-pci.txt
new file mode 100644 (file)
index 0000000..3d21791
--- /dev/null
@@ -0,0 +1,59 @@
+TI PCI Controllers
+
+PCIe Designware Controller
+ - compatible: Should be "ti,dra7-pcie""
+ - reg : Two register ranges as listed in the reg-names property
+ - reg-names : The first entry must be "ti-conf" for the TI specific registers
+              The second entry must be "rc-dbics" for the designware pcie
+              registers
+              The third entry must be "config" for the PCIe configuration space
+ - phys : list of PHY specifiers (used by generic PHY framework)
+ - phy-names : must be "pcie-phy0", "pcie-phy1", "pcie-phyN".. based on the
+              number of PHYs as specified in *phys* property.
+ - ti,hwmods : Name of the hwmod associated to the pcie, "pcie<X>",
+              where <X> is the instance number of the pcie from the HW spec.
+ - interrupts : Two interrupt entries must be specified. The first one is for
+               main interrupt line and the second for MSI interrupt line.
+ - #address-cells,
+   #size-cells,
+   #interrupt-cells,
+   device_type,
+   ranges,
+   num-lanes,
+   interrupt-map-mask,
+   interrupt-map : as specified in ../designware-pcie.txt
+
+Example:
+axi {
+       compatible = "simple-bus";
+       #size-cells = <1>;
+       #address-cells = <1>;
+       ranges = <0x51000000 0x51000000 0x3000
+                 0x0        0x20000000 0x10000000>;
+       pcie@51000000 {
+               compatible = "ti,dra7-pcie";
+               reg = <0x51000000 0x2000>, <0x51002000 0x14c>, <0x1000 0x2000>;
+               reg-names = "rc_dbics", "ti_conf", "config";
+               interrupts = <0 232 0x4>, <0 233 0x4>;
+               #address-cells = <3>;
+               #size-cells = <2>;
+               device_type = "pci";
+               ranges = <0x81000000 0 0          0x03000 0 0x00010000
+                         0x82000000 0 0x20013000 0x13000 0 0xffed000>;
+               #interrupt-cells = <1>;
+               num-lanes = <1>;
+               ti,hwmods = "pcie1";
+               phys = <&pcie1_phy>;
+               phy-names = "pcie-phy0";
+               interrupt-map-mask = <0 0 0 7>;
+               interrupt-map = <0 0 0 1 &pcie_intc 1>,
+                               <0 0 0 2 &pcie_intc 2>,
+                               <0 0 0 3 &pcie_intc 3>,
+                               <0 0 0 4 &pcie_intc 4>;
+               pcie_intc: interrupt-controller {
+                       interrupt-controller;
+                       #address-cells = <0>;
+                       #interrupt-cells = <1>;
+               };
+       };
+};
index 0211c6d8a5229e17866eb90f751a015ffaf609a0..92fae82f35f2174ca64cb6de14825245870d9f5f 100644 (file)
@@ -62,7 +62,7 @@ Example:
                #gpio-cells = <2>;
                interrupt-controller;
                #interrupt-cells = <2>;
-               interrupts = <0 32 0x4>;
+               interrupts = <0 16 0x4>;
 
                pinctrl-names = "default";
                pinctrl-0 = <&gsbi5_uart_default>;
index 340980239ea9f7e1fb35f59da3ebcc0bf5b96ef8..ca69f5e3040cfa48299682dd6371f99c90b49ffa 100644 (file)
@@ -45,8 +45,8 @@ Example:
                infet5-supply = <&some_reg>;
                infet6-supply = <&some_reg>;
                infet7-supply = <&some_reg>;
-               vsys_l1-supply = <&some_reg>;
-               vsys_l2-supply = <&some_reg>;
+               vsys-l1-supply = <&some_reg>;
+               vsys-l2-supply = <&some_reg>;
 
                regulators {
                        dcdc1 {
index 46f344965313f1081dbd7894e738795a8b935815..4eb7997674a09006dfa0a991b634082ddc64974d 100644 (file)
@@ -1,7 +1,7 @@
 ADI AXI-SPDIF controller
 
 Required properties:
- - compatible : Must be "adi,axi-spdif-1.00.a"
+ - compatible : Must be "adi,axi-spdif-tx-1.00.a"
  - reg : Must contain SPDIF core's registers location and length
  - clocks : Pairs of phandle and specifier referencing the controller's clocks.
    The controller expects two clocks, the clock used for the AXI interface and
index 67a4087d53f9c731a1c0bf57e3ec48b7c1b90610..bb9753b635a3a5e8d8f794814a83584878b550e5 100644 (file)
@@ -56,10 +56,10 @@ The dma_buf buffer sharing API usage contains the following steps:
                                     size_t size, int flags,
                                     const char *exp_name)
 
-   If this succeeds, dma_buf_export allocates a dma_buf structure, and returns a
-   pointer to the same. It also associates an anonymous file with this buffer,
-   so it can be exported. On failure to allocate the dma_buf object, it returns
-   NULL.
+   If this succeeds, dma_buf_export_named allocates a dma_buf structure, and
+   returns a pointer to the same. It also associates an anonymous file with this
+   buffer, so it can be exported. On failure to allocate the dma_buf object,
+   it returns NULL.
 
    'exp_name' is the name of exporter - to facilitate information while
    debugging.
@@ -76,7 +76,7 @@ The dma_buf buffer sharing API usage contains the following steps:
    drivers and/or processes.
 
    Interface:
-      int dma_buf_fd(struct dma_buf *dmabuf)
+      int dma_buf_fd(struct dma_buf *dmabuf, int flags)
 
    This API installs an fd for the anonymous file associated with this buffer;
    returns either 'fd', or error.
@@ -157,7 +157,9 @@ to request use of buffer for allocation.
    "dma_buf->ops->" indirection from the users of this interface.
 
    In struct dma_buf_ops, unmap_dma_buf is defined as
-      void (*unmap_dma_buf)(struct dma_buf_attachment *, struct sg_table *);
+      void (*unmap_dma_buf)(struct dma_buf_attachment *,
+                            struct sg_table *,
+                            enum dma_data_direction);
 
    unmap_dma_buf signifies the end-of-DMA for the attachment provided. Like
    map_dma_buf, this API also must be implemented by the exporter.
index b18dd17790299de1b01053117a065af1ed7f251f..f1997e9da61f1cb2fbb122b610c648c537520185 100644 (file)
@@ -349,7 +349,11 @@ prototypes:
 locking rules:
                        inode->i_lock   may block
 fl_copy_lock:          yes             no
-fl_release_private:    maybe           no
+fl_release_private:    maybe           maybe[1]
+
+[1]:   ->fl_release_private for flock or POSIX locks is currently allowed
+to block. Leases however can still be freed while the i_lock is held and
+so fl_release_private called on a lease should not block.
 
 ----------------------- lock_manager_operations ---------------------------
 prototypes:
index e386f7e4bcee1e4c8d5b0f08872c877097e6f9f9..724043858b0834f874aff57df4155f1da3dffad8 100644 (file)
@@ -138,9 +138,9 @@ Installation
   - Build, install, reboot
 
     The NFS/RDMA code will be enabled automatically if NFS and RDMA
-    are turned on. The NFS/RDMA client and server are configured via the hidden
-    SUNRPC_XPRT_RDMA config option that depends on SUNRPC and INFINIBAND. The
-    value of SUNRPC_XPRT_RDMA will be:
+    are turned on. The NFS/RDMA client and server are configured via the
+    SUNRPC_XPRT_RDMA_CLIENT and SUNRPC_XPRT_RDMA_SERVER config options that both
+    depend on SUNRPC and INFINIBAND. The default value of both options will be:
 
      - N if either SUNRPC or INFINIBAND are N, in this case the NFS/RDMA client
        and server will not be built
@@ -235,8 +235,9 @@ NFS/RDMA Setup
 
   - Start the NFS server
 
-    If the NFS/RDMA server was built as a module (CONFIG_SUNRPC_XPRT_RDMA=m in
-    kernel config), load the RDMA transport module:
+    If the NFS/RDMA server was built as a module
+    (CONFIG_SUNRPC_XPRT_RDMA_SERVER=m in kernel config), load the RDMA
+    transport module:
 
     $ modprobe svcrdma
 
@@ -255,8 +256,9 @@ NFS/RDMA Setup
 
   - On the client system
 
-    If the NFS/RDMA client was built as a module (CONFIG_SUNRPC_XPRT_RDMA=m in
-    kernel config), load the RDMA client module:
+    If the NFS/RDMA client was built as a module
+    (CONFIG_SUNRPC_XPRT_RDMA_CLIENT=m in kernel config), load the RDMA client
+    module:
 
     $ modprobe xprtrdma.ko
 
index 1fe0ccb1af553b8307999bb0a7cb997326cc44ad..8ea3e90ace07a945ef6fd512396f18ef259754a2 100644 (file)
@@ -235,6 +235,39 @@ be used for more than one file, you can store an arbitrary pointer in the
 private field of the seq_file structure; that value can then be retrieved
 by the iterator functions.
 
+There is also a wrapper function to seq_open() called seq_open_private(). It
+kmallocs a zero filled block of memory and stores a pointer to it in the
+private field of the seq_file structure, returning 0 on success. The
+block size is specified in a third parameter to the function, e.g.:
+
+       static int ct_open(struct inode *inode, struct file *file)
+       {
+               return seq_open_private(file, &ct_seq_ops,
+                                       sizeof(struct mystruct));
+       }
+
+There is also a variant function, __seq_open_private(), which is functionally
+identical except that, if successful, it returns the pointer to the allocated
+memory block, allowing further initialisation e.g.:
+
+       static int ct_open(struct inode *inode, struct file *file)
+       {
+               struct mystruct *p =
+                       __seq_open_private(file, &ct_seq_ops, sizeof(*p));
+
+               if (!p)
+                       return -ENOMEM;
+
+               p->foo = bar; /* initialize my stuff */
+                       ...
+               p->baz = true;
+
+               return 0;
+       }
+
+A corresponding close function, seq_release_private() is available which
+frees the memory allocated in the corresponding open.
+
 The other operations of interest - read(), llseek(), and release() - are
 all implemented by the seq_file code itself. So a virtual file's
 file_operations structure will look like:
index 76546324e968cf70394144beb86817c16586ceb3..6ce544191ca6b6d648cc2d66ed3df8fb7191d871 100644 (file)
@@ -53,7 +53,20 @@ with IS_ERR() (they will never return a NULL pointer). -ENOENT will be returned
 if and only if no GPIO has been assigned to the device/function/index triplet,
 other error codes are used for cases where a GPIO has been assigned but an error
 occurred while trying to acquire it. This is useful to discriminate between mere
-errors and an absence of GPIO for optional GPIO parameters.
+errors and an absence of GPIO for optional GPIO parameters. For the common
+pattern where a GPIO is optional, the gpiod_get_optional() and
+gpiod_get_index_optional() functions can be used. These functions return NULL
+instead of -ENOENT if no GPIO has been assigned to the requested function:
+
+
+       struct gpio_desc *gpiod_get_optional(struct device *dev,
+                                            const char *con_id,
+                                            enum gpiod_flags flags)
+
+       struct gpio_desc *gpiod_get_index_optional(struct device *dev,
+                                                  const char *con_id,
+                                                  unsigned int index,
+                                                  enum gpiod_flags flags)
 
 Device-managed variants of these functions are also defined:
 
@@ -65,6 +78,15 @@ Device-managed variants of these functions are also defined:
                                               unsigned int idx,
                                               enum gpiod_flags flags)
 
+       struct gpio_desc *devm_gpiod_get_optional(struct device *dev,
+                                                 const char *con_id,
+                                                 enum gpiod_flags flags)
+
+       struct gpio_desc * devm_gpiod_get_index_optional(struct device *dev,
+                                                       const char *con_id,
+                                                       unsigned int index,
+                                                       enum gpiod_flags flags)
+
 A GPIO descriptor can be disposed of using the gpiod_put() function:
 
        void gpiod_put(struct gpio_desc *desc)
index 3e742ba25536123dc4108c6eb2db860584d9b442..2ac78ae1039de5c6bf44b4b32e41de7d742be1d6 100644 (file)
@@ -57,12 +57,12 @@ Well, you are all set up now. You can now use SMBus commands or plain
 I2C to communicate with your device. SMBus commands are preferred if
 the device supports them. Both are illustrated below.
 
-  __u8 register = 0x10; /* Device register to access */
+  __u8 reg = 0x10; /* Device register to access */
   __s32 res;
   char buf[10];
 
   /* Using SMBus commands */
-  res = i2c_smbus_read_word_data(file, register);
+  res = i2c_smbus_read_word_data(file, reg);
   if (res < 0) {
     /* ERROR HANDLING: i2c transaction failed */
   } else {
@@ -70,11 +70,11 @@ the device supports them. Both are illustrated below.
   }
 
   /* Using I2C Write, equivalent of 
-     i2c_smbus_write_word_data(file, register, 0x6543) */
-  buf[0] = register;
+     i2c_smbus_write_word_data(file, reg, 0x6543) */
+  buf[0] = reg;
   buf[1] = 0x43;
   buf[2] = 0x65;
-  if (write(file, buf, 3) ! =3) {
+  if (write(file, buf, 3) !3) {
     /* ERROR HANDLING: i2c transaction failed */
   }
 
index 88d5a863712a53091dc79210f356599977dc0d9c..6c0b9f27e4652c94616ce32643a7fbe32d370eda 100644 (file)
@@ -18,7 +18,7 @@ memory image to a dump file on the local disk, or across the network to
 a remote system.
 
 Kdump and kexec are currently supported on the x86, x86_64, ppc64, ia64,
-and s390x architectures.
+s390x and arm architectures.
 
 When the system kernel boots, it reserves a small section of memory for
 the dump-capture kernel. This ensures that ongoing Direct Memory Access
@@ -112,7 +112,7 @@ There are two possible methods of using Kdump.
 2) Or use the system kernel binary itself as dump-capture kernel and there is
    no need to build a separate dump-capture kernel. This is possible
    only with the architectures which support a relocatable kernel. As
-   of today, i386, x86_64, ppc64 and ia64 architectures support relocatable
+   of today, i386, x86_64, ppc64, ia64 and arm architectures support relocatable
    kernel.
 
 Building a relocatable kernel is advantageous from the point of view that
@@ -241,6 +241,13 @@ Dump-capture kernel config options (Arch Dependent, ia64)
   kernel will be aligned to 64Mb, so if the start address is not then
   any space below the alignment point will be wasted.
 
+Dump-capture kernel config options (Arch Dependent, arm)
+----------------------------------------------------------
+
+-   To use a relocatable kernel,
+    Enable "AUTO_ZRELADDR" support under "Boot" options:
+
+    AUTO_ZRELADDR=y
 
 Extended crashkernel syntax
 ===========================
@@ -256,6 +263,10 @@ The syntax is:
     crashkernel=<range1>:<size1>[,<range2>:<size2>,...][@offset]
     range=start-[end]
 
+Please note, on arm, the offset is required.
+    crashkernel=<range1>:<size1>[,<range2>:<size2>,...]@offset
+    range=start-[end]
+
     'start' is inclusive and 'end' is exclusive.
 
 For example:
@@ -296,6 +307,12 @@ Boot into System Kernel
    on the memory consumption of the kdump system. In general this is not
    dependent on the memory size of the production system.
 
+   On arm, use "crashkernel=Y@X". Note that the start address of the kernel
+   will be aligned to 128MiB (0x08000000), so if the start address is not then
+   any space below the alignment point may be overwritten by the dump-capture kernel,
+   which means it is possible that the vmcore is not that precise as expected.
+
+
 Load the Dump-capture Kernel
 ============================
 
@@ -315,7 +332,8 @@ For ia64:
        - Use vmlinux or vmlinuz.gz
 For s390x:
        - Use image or bzImage
-
+For arm:
+       - Use zImage
 
 If you are using a uncompressed vmlinux image then use following command
 to load dump-capture kernel.
@@ -331,6 +349,15 @@ to load dump-capture kernel.
    --initrd=<initrd-for-dump-capture-kernel> \
    --append="root=<root-dev> <arch-specific-options>"
 
+If you are using a compressed zImage, then use following command
+to load dump-capture kernel.
+
+   kexec --type zImage -p <dump-capture-kernel-bzImage> \
+   --initrd=<initrd-for-dump-capture-kernel> \
+   --dtb=<dtb-for-dump-capture-kernel> \
+   --append="root=<root-dev> <arch-specific-options>"
+
+
 Please note, that --args-linux does not need to be specified for ia64.
 It is planned to make this a no-op on that architecture, but for now
 it should be omitted
@@ -347,6 +374,9 @@ For ppc64:
 For s390x:
        "1 maxcpus=1 cgroup_disable=memory"
 
+For arm:
+       "1 maxcpus=1 reset_devices"
+
 Notes on loading the dump-capture kernel:
 
 * By default, the ELF headers are stored in ELF64 format to support
index d399ae1fc724aaaf4bd52a20f4a08387970eddc7..a3b4f209e562ff7ba2ce2da2a5cc1dae09f6fa3d 100644 (file)
@@ -18,3 +18,5 @@ sonypi.txt
        - info on Linux Sony Programmable I/O Device support.
 thinkpad-acpi.txt
        - information on the (IBM and Lenovo) ThinkPad ACPI Extras driver.
+toshiba_haps.txt
+       - information on the Toshiba HDD Active Protection Sensor driver.
diff --git a/Documentation/laptops/toshiba_haps.txt b/Documentation/laptops/toshiba_haps.txt
new file mode 100644 (file)
index 0000000..11dbcfd
--- /dev/null
@@ -0,0 +1,76 @@
+Kernel driver toshiba_haps
+Toshiba HDD Active Protection Sensor
+====================================
+
+Author: Azael Avalos <coproscefalo@gmail.com>
+
+
+0. Contents
+-----------
+
+1. Description
+2. Interface
+3. Accelerometer axes
+4. Supported devices
+5. Usage
+
+
+1. Description
+--------------
+
+This driver provides support for the accelerometer found in various Toshiba
+laptops, being called "Toshiba HDD Protection - Shock Sensor" officialy,
+and detects laptops automatically with this device.
+On Windows, Toshiba provided software monitors this device and provides
+automatic HDD protection (head unload) on sudden moves or harsh vibrations,
+however, this driver only provides a notification via a sysfs file to let
+userspace tools or daemons act accordingly, as well as providing a sysfs
+file to set the desired protection level or sensor sensibility.
+
+
+2. Interface
+------------
+
+This device comes with 3 methods:
+_STA -  Checks existence of the device, returning Zero if the device does not
+       exists or is not supported.
+PTLV -  Sets the desired protection level.
+RSSS -  Shuts down the HDD protection interface for a few seconds,
+       then restores normal operation.
+
+Note:
+The presence of Solid State Drives (SSD) can make this driver to fail loading,
+given the fact that such drives have no movable parts, and thus, not requiring
+any "protection" as well as failing during the evaluation of the _STA method
+found under this device.
+
+
+3. Accelerometer axes
+---------------------
+
+This device does not report any axes, however, to query the sensor position
+a couple HCI (Hardware Configuration Interface) calls (0x6D and 0xA6) are
+provided to query such information, handled by the kernel module toshiba_acpi
+since kernel version 3.15.
+
+
+4. Supported devices
+--------------------
+
+This driver binds itself to the ACPI device TOS620A, and any Toshiba laptop
+with this device is supported, given the fact that they have the presence of
+conventional HDD and not only SSD, or a combination of both HDD and SSD.
+
+
+5. Usage
+--------
+
+The sysfs files under /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS620A:00/ are:
+protection_level - The protection_level is readable and writeable, and
+                  provides a way to let userspace query the current protection
+                  level, as well as set the desired protection level, the
+                  available protection levels are:
+                  0 - Disabled | 1 - Low | 2 - Medium | 3 - High
+reset_protection - The reset_protection entry is writeable only, being "1"
+                  the only parameter it accepts, it is used to trigger
+                  a reset of the protection interface.
index af815b9ba413afc6ba3e21beac2d613e771e0bdb..f89960a0ff95e6e0c5e870f67c836be6adb9e0e6 100644 (file)
@@ -59,7 +59,7 @@ acts similar to /dev/rtc and reacts on free-fall interrupts received
 from the device. It supports blocking operations, poll/select and
 fasync operation modes. You must read 1 bytes from the device.  The
 result is number of free-fall interrupts since the last successful
-read (or 255 if number of interrupts would not fit). See the hpfall.c
+read (or 255 if number of interrupts would not fit). See the freefall.c
 file for an example on using the device.
 
 
index c48a9704bda8eaae5851bf54a0b0277cd01c88b4..81916ab5d96f9584adf1a4f56adea8f79d3f1ec2 100644 (file)
@@ -951,7 +951,7 @@ Size modifier is one of ...
 
 Mode modifier is one of:
 
-  BPF_IMM  0x00  /* classic BPF only, reserved in eBPF */
+  BPF_IMM  0x00  /* used for 32-bit mov in classic BPF and 64-bit in eBPF */
   BPF_ABS  0x20
   BPF_IND  0x40
   BPF_MEM  0x60
@@ -995,6 +995,12 @@ BPF_XADD | BPF_DW | BPF_STX: lock xadd *(u64 *)(dst_reg + off16) += src_reg
 Where size is one of: BPF_B or BPF_H or BPF_W or BPF_DW. Note that 1 and
 2 byte atomic increments are not supported.
 
+eBPF has one 16-byte instruction: BPF_LD | BPF_DW | BPF_IMM which consists
+of two consecutive 'struct bpf_insn' 8-byte blocks and interpreted as single
+instruction that loads 64-bit immediate value into a dst_reg.
+Classic BPF has similar instruction: BPF_LD | BPF_W | BPF_IMM which loads
+32-bit immediate value into a register.
+
 Testing
 -------
 
index 29a93518bf18acc7d9a0a3ac443abd03662e3792..db2383cb1df9a71d051aafe581f4e44f85bba0d9 100644 (file)
@@ -65,6 +65,12 @@ neigh/default/gc_thresh1 - INTEGER
        purge entries if there are fewer than this number.
        Default: 128
 
+neigh/default/gc_thresh2 - INTEGER
+       Threshold when garbage collector becomes more aggressive about
+       purging entries. Entries older than 5 seconds will be cleared
+       when over this number.
+       Default: 512
+
 neigh/default/gc_thresh3 - INTEGER
        Maximum number of neighbor entries allowed.  Increase this
        when using large numbers of interfaces and when communicating
@@ -838,6 +844,11 @@ igmp_max_memberships - INTEGER
 
        conf/all/*        is special, changes the settings for all interfaces
 
+igmp_qrv - INTEGER
+        Controls the IGMP query robustness variable (see RFC2236 8.1).
+        Default: 2 (as specified by RFC2236 8.1)
+        Minimum: 1 (as specified by RFC6636 4.5)
+
 log_martians - BOOLEAN
        Log packets with impossible addresses to kernel log.
        log_martians for the interface will be enabled if at least one of
@@ -1146,6 +1157,11 @@ anycast_src_echo_reply - BOOLEAN
        FALSE: disabled
        Default: FALSE
 
+mld_qrv - INTEGER
+       Controls the MLD query robustness variable (see RFC3810 9.1).
+       Default: 2 (as specified by RFC3810 9.1)
+       Minimum: 1 (as specified by RFC6636 4.5)
+
 IPv6 Fragmentation:
 
 ip6frag_high_thresh - INTEGER
index 897f942b976bd61597d5dd49ceb17cf24a0bc70d..412f45ca2d73e3cd31a487e5fe13b73fc552d9f5 100644 (file)
-The existing interfaces for getting network packages time stamped are:
+
+1. Control Interfaces
+
+The interfaces for receiving network packages timestamps are:
 
 * SO_TIMESTAMP
-  Generate time stamp for each incoming packet using the (not necessarily
-  monotonous!) system time. Result is returned via recv_msg() in a
-  control message as timeval (usec resolution).
+  Generates a timestamp for each incoming packet in (not necessarily
+  monotonic) system time. Reports the timestamp via recvmsg() in a
+  control message as struct timeval (usec resolution).
 
 * SO_TIMESTAMPNS
-  Same time stamping mechanism as SO_TIMESTAMP, but returns result as
-  timespec (nsec resolution).
+  Same timestamping mechanism as SO_TIMESTAMP, but reports the
+  timestamp as struct timespec (nsec resolution).
 
 * IP_MULTICAST_LOOP + SO_TIMESTAMP[NS]
-  Only for multicasts: approximate send time stamp by receiving the looped
-  packet and using its receive time stamp.
+  Only for multicast:approximate transmit timestamp obtained by
+  reading the looped packet receive timestamp.
 
-The following interface complements the existing ones: receive time
-stamps can be generated and returned for arbitrary packets and much
-closer to the point where the packet is really sent. Time stamps can
-be generated in software (as before) or in hardware (if the hardware
-has such a feature).
+* SO_TIMESTAMPING
+  Generates timestamps on reception, transmission or both. Supports
+  multiple timestamp sources, including hardware. Supports generating
+  timestamps for stream sockets.
 
-SO_TIMESTAMPING:
 
-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.
+1.1 SO_TIMESTAMP:
 
-Four of the bits are requests to the stack to try to generate
-timestamps.  Any combination of them is valid.
+This socket option enables timestamping of datagrams on the reception
+path. Because the destination socket, if any, is not known early in
+the network stack, the feature has to be enabled for all packets. The
+same is true for all early receive timestamp options.
 
-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
+For interface details, see `man 7 socket`.
+
+
+1.2 SO_TIMESTAMPNS:
+
+This option is identical to SO_TIMESTAMP except for the returned data type.
+Its struct timespec allows for higher resolution (ns) timestamps than the
+timeval of SO_TIMESTAMP (ms).
+
+
+1.3 SO_TIMESTAMPING:
+
+Supports multiple types of timestamp requests. As a result, this
+socket option takes a bitmap of flags, not a boolean. In
+
+  err = setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING, (void *) val, &val);
+
+val is an integer with any of the following bits set. Setting other
+bit returns EINVAL and does not change the current state.
 
-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 (deprecated)
-SOF_TIMESTAMPING_RAW_HARDWARE: report hwtimeraw if available
+1.3.1 Timestamp Generation
 
-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.
+Some bits are requests to the stack to try to generate timestamps. Any
+combination of them is valid. Changes to these bits apply to newly
+created packets, not to packets already in the stack. As a result, it
+is possible to selectively request timestamps for a subset of packets
+(e.g., for sampling) by embedding an send() call within two setsockopt
+calls, one to enable timestamp generation and one to disable it.
+Timestamps may also be generated for reasons other than being
+requested by a particular socket, such as when receive timestamping is
+enabled system wide, as explained earlier.
 
-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:
+SOF_TIMESTAMPING_RX_HARDWARE:
+  Request rx timestamps generated by the network adapter.
+
+SOF_TIMESTAMPING_RX_SOFTWARE:
+  Request rx timestamps when data enters the kernel. These timestamps
+  are generated just after a device driver hands a packet to the
+  kernel receive stack.
+
+SOF_TIMESTAMPING_TX_HARDWARE:
+  Request tx timestamps generated by the network adapter.
+
+SOF_TIMESTAMPING_TX_SOFTWARE:
+  Request tx timestamps when data leaves the kernel. These timestamps
+  are generated in the device driver as close as possible, but always
+  prior to, passing the packet to the network interface. Hence, they
+  require driver support and may not be available for all devices.
+
+SOF_TIMESTAMPING_TX_SCHED:
+  Request tx timestamps prior to entering the packet scheduler. Kernel
+  transmit latency is, if long, often dominated by queuing delay. The
+  difference between this timestamp and one taken at
+  SOF_TIMESTAMPING_TX_SOFTWARE will expose this latency independent
+  of protocol processing. The latency incurred in protocol
+  processing, if any, can be computed by subtracting a userspace
+  timestamp taken immediately before send() from this timestamp. On
+  machines with virtual devices where a transmitted packet travels
+  through multiple devices and, hence, multiple packet schedulers,
+  a timestamp is generated at each layer. This allows for fine
+  grained measurement of queuing delay.
+
+SOF_TIMESTAMPING_TX_ACK:
+  Request tx timestamps when all data in the send buffer has been
+  acknowledged. This only makes sense for reliable protocols. It is
+  currently only implemented for TCP. For that protocol, it may
+  over-report measurement, because the timestamp is generated when all
+  data up to and including the buffer at send() was acknowledged: the
+  cumulative acknowledgment. The mechanism ignores SACK and FACK.
+
+
+1.3.2 Timestamp Reporting
+
+The other three bits control which timestamps will be reported in a
+generated control message. Changes to the bits take immediate
+effect at the timestamp reporting locations in the stack. Timestamps
+are only reported for packets that also have the relevant timestamp
+generation request set.
+
+SOF_TIMESTAMPING_SOFTWARE:
+  Report any software timestamps when available.
+
+SOF_TIMESTAMPING_SYS_HARDWARE:
+  This option is deprecated and ignored.
+
+SOF_TIMESTAMPING_RAW_HARDWARE:
+  Report hardware timestamps as generated by
+  SOF_TIMESTAMPING_TX_HARDWARE when available.
+
+
+1.3.3 Timestamp Options
+
+The interface supports one option
+
+SOF_TIMESTAMPING_OPT_ID:
+
+  Generate a unique identifier along with each packet. A process can
+  have multiple concurrent timestamping requests outstanding. Packets
+  can be reordered in the transmit path, for instance in the packet
+  scheduler. In that case timestamps will be queued onto the error
+  queue out of order from the original send() calls. This option
+  embeds a counter that is incremented at send() time, to order
+  timestamps within a flow.
+
+  This option is implemented only for transmit timestamps. There, the
+  timestamp is always looped along with a struct sock_extended_err.
+  The option modifies field ee_info to pass an id that is unique
+  among all possibly concurrently outstanding timestamp requests for
+  that socket. In practice, it is a monotonically increasing u32
+  (that wraps).
+
+  In datagram sockets, the counter increments on each send call. In
+  stream sockets, it increments with every byte.
+
+
+1.4 Bytestream Timestamps
+
+The SO_TIMESTAMPING interface supports timestamping of bytes in a
+bytestream. Each request is interpreted as a request for when the
+entire contents of the buffer has passed a timestamping point. That
+is, for streams option SOF_TIMESTAMPING_TX_SOFTWARE will record
+when all bytes have reached the device driver, regardless of how
+many packets the data has been converted into.
+
+In general, bytestreams have no natural delimiters and therefore
+correlating a timestamp with data is non-trivial. A range of bytes
+may be split across segments, any segments may be merged (possibly
+coalescing sections of previously segmented buffers associated with
+independent send() calls). Segments can be reordered and the same
+byte range can coexist in multiple segments for protocols that
+implement retransmissions.
+
+It is essential that all timestamps implement the same semantics,
+regardless of these possible transformations, as otherwise they are
+incomparable. Handling "rare" corner cases differently from the
+simple case (a 1:1 mapping from buffer to skb) is insufficient
+because performance debugging often needs to focus on such outliers.
+
+In practice, timestamps can be correlated with segments of a
+bytestream consistently, if both semantics of the timestamp and the
+timing of measurement are chosen correctly. This challenge is no
+different from deciding on a strategy for IP fragmentation. There, the
+definition is that only the first fragment is timestamped. For
+bytestreams, we chose that a timestamp is generated only when all
+bytes have passed a point. SOF_TIMESTAMPING_TX_ACK as defined is easy to
+implement and reason about. An implementation that has to take into
+account SACK would be more complex due to possible transmission holes
+and out of order arrival.
+
+On the host, TCP can also break the simple 1:1 mapping from buffer to
+skbuff as a result of Nagle, cork, autocork, segmentation and GSO. The
+implementation ensures correctness in all cases by tracking the
+individual last byte passed to send(), even if it is no longer the
+last byte after an skbuff extend or merge operation. It stores the
+relevant sequence number in skb_shinfo(skb)->tskey. Because an skbuff
+has only one such field, only one timestamp can be generated.
+
+In rare cases, a timestamp request can be missed if two requests are
+collapsed onto the same skb. A process can detect this situation by
+enabling SOF_TIMESTAMPING_OPT_ID and comparing the byte offset at
+send time with the value returned for each timestamp. It can prevent
+the situation by always flushing the TCP stack in between requests,
+for instance by enabling TCP_NODELAY and disabling TCP_CORK and
+autocork.
+
+These precautions ensure that the timestamp is generated only when all
+bytes have passed a timestamp point, assuming that the network stack
+itself does not reorder the segments. The stack indeed tries to avoid
+reordering. The one exception is under administrator control: it is
+possible to construct a packet scheduler configuration that delays
+segments from the same stream differently. Such a setup would be
+unusual.
+
+
+2 Data Interfaces
+
+Timestamps are read using the ancillary data feature of recvmsg().
+See `man 3 cmsg` for details of this interface. The socket manual
+page (`man 7 socket`) describes how timestamps generated with
+SO_TIMESTAMP and SO_TIMESTAMPNS records can be retrieved.
+
+
+2.1 SCM_TIMESTAMPING records
+
+These timestamps are returned in a control message with cmsg_level
+SOL_SOCKET, cmsg_type SCM_TIMESTAMPING, and payload of type
 
 struct scm_timestamping {
-       struct timespec systime;
-       struct timespec hwtimetrans;
-       struct timespec hwtimeraw;
+       struct timespec ts[3];
 };
 
-recvmsg() can be used to get this control message for regular incoming
-packets. For send time stamps the outgoing packet is looped back to
-the socket's error queue with the send time stamp(s) attached. It can
-be received with recvmsg(flags=MSG_ERRQUEUE). The call returns the
-original outgoing packet data including all headers preprended down to
-and including the link layer, the scm_timestamping control message and
-a sock_extended_err control message with ee_errno==ENOMSG and
-ee_origin==SO_EE_ORIGIN_TIMESTAMPING. A socket with such a pending
-bounced packet is ready for reading as far as select() is concerned.
-If the outgoing packet has to be fragmented, then only the first
-fragment is time stamped and returned to the sending socket.
-
-All three values correspond to the same event in time, but were
-generated in different ways. Each of these values may be empty (= all
-zero), in which case no such value was available. If the application
-is not interested in some of these values, they can be left blank to
-avoid the potential overhead of calculating them.
-
-systime is the value of the system time at that moment. This
-corresponds to the value also returned via SO_TIMESTAMP[NS]. If the
-time stamp was generated by hardware, then this field is
-empty. Otherwise it is filled in if SOF_TIMESTAMPING_SOFTWARE is
-set.
-
-hwtimeraw is the original hardware time stamp. Filled in if
-SOF_TIMESTAMPING_RAW_HARDWARE is set. No assumptions about its
-relation to system time should be made.
-
-hwtimetrans is always zero. This field is deprecated. It used to hold
-hw timestamps converted to system time. Instead, expose the hardware
-clock device on the NIC directly as a HW PTP clock source, to allow
-time conversion in userspace and optionally synchronize system time
-with a userspace PTP stack such as linuxptp. For the PTP clock API,
-see Documentation/ptp/ptp.txt.
-
-
-SIOCSHWTSTAMP, SIOCGHWTSTAMP:
+The structure can return up to three timestamps. This is a legacy
+feature. Only one field is non-zero at any time. Most timestamps
+are passed in ts[0]. Hardware timestamps are passed in ts[2].
+
+ts[1] used to hold hardware timestamps converted to system time.
+Instead, expose the hardware clock device on the NIC directly as
+a HW PTP clock source, to allow time conversion in userspace and
+optionally synchronize system time with a userspace PTP stack such
+as linuxptp. For the PTP clock API, see Documentation/ptp/ptp.txt.
+
+2.1.1 Transmit timestamps with MSG_ERRQUEUE
+
+For transmit timestamps the outgoing packet is looped back to the
+socket's error queue with the send timestamp(s) attached. A process
+receives the timestamps by calling recvmsg() with flag MSG_ERRQUEUE
+set and with a msg_control buffer sufficiently large to receive the
+relevant metadata structures. The recvmsg call returns the original
+outgoing data packet with two ancillary messages attached.
+
+A message of cm_level SOL_IP(V6) and cm_type IP(V6)_RECVERR
+embeds a struct sock_extended_err. This defines the error type. For
+timestamps, the ee_errno field is ENOMSG. The other ancillary message
+will have cm_level SOL_SOCKET and cm_type SCM_TIMESTAMPING. This
+embeds the struct scm_timestamping.
+
+
+2.1.1.2 Timestamp types
+
+The semantics of the three struct timespec are defined by field
+ee_info in the extended error structure. It contains a value of
+type SCM_TSTAMP_* to define the actual timestamp passed in
+scm_timestamping.
+
+The SCM_TSTAMP_* types are 1:1 matches to the SOF_TIMESTAMPING_*
+control fields discussed previously, with one exception. For legacy
+reasons, SCM_TSTAMP_SND is equal to zero and can be set for both
+SOF_TIMESTAMPING_TX_HARDWARE and SOF_TIMESTAMPING_TX_SOFTWARE. It
+is the first if ts[2] is non-zero, the second otherwise, in which
+case the timestamp is stored in ts[0].
+
+
+2.1.1.3 Fragmentation
+
+Fragmentation of outgoing datagrams is rare, but is possible, e.g., by
+explicitly disabling PMTU discovery. If an outgoing packet is fragmented,
+then only the first fragment is timestamped and returned to the sending
+socket.
+
+
+2.1.1.4 Packet Payload
+
+The calling application is often not interested in receiving the whole
+packet payload that it passed to the stack originally: the socket
+error queue mechanism is just a method to piggyback the timestamp on.
+In this case, the application can choose to read datagrams with a
+smaller buffer, possibly even of length 0. The payload is truncated
+accordingly. Until the process calls recvmsg() on the error queue,
+however, the full packet is queued, taking up budget from SO_RCVBUF.
+
+
+2.1.1.5 Blocking Read
+
+Reading from the error queue is always a non-blocking operation. To
+block waiting on a timestamp, use poll or select. poll() will return
+POLLERR in pollfd.revents if any data is ready on the error queue.
+There is no need to pass this flag in pollfd.events. This flag is
+ignored on request. See also `man 2 poll`.
+
+
+2.1.2 Receive timestamps
+
+On reception, there is no reason to read from the socket error queue.
+The SCM_TIMESTAMPING ancillary data is sent along with the packet data
+on a normal recvmsg(). Since this is not a socket error, it is not
+accompanied by a message SOL_IP(V6)/IP(V6)_RECVERROR. In this case,
+the meaning of the three fields in struct scm_timestamping is
+implicitly defined. ts[0] holds a software timestamp if set, ts[1]
+is again deprecated and ts[2] holds a hardware timestamp if set.
+
+
+3. Hardware Timestamping configuration: SIOCSHWTSTAMP and SIOCGHWTSTAMP
 
 Hardware time stamping must also be initialized for each device driver
 that is expected to do hardware time stamping. The parameter is defined in
@@ -167,8 +372,7 @@ enum {
         */
 };
 
-
-DEVICE IMPLEMENTATION
+3.1 Hardware Timestamping Implementation: Device Drivers
 
 A driver which supports hardware time stamping must support the
 SIOCSHWTSTAMP ioctl and update the supplied struct hwtstamp_config with
index d934afc8306a495134bf24559c6ecbd94178f36f..95e239c7007646cec7e3ee8646926a02af89f0ff 100644 (file)
@@ -1,14 +1,20 @@
+# To compile, from the source root
+#
+#    make headers_install
+#    make M=documentation
+
 # kbuild trick to avoid linker error. Can be omitted if a module is built.
 obj- := dummy.o
 
 # List of programs to build
-hostprogs-y := timestamping hwtstamp_config
+hostprogs-y := timestamping txtimestamp hwtstamp_config
 
 # Tell kbuild to always build the programs
 always := $(hostprogs-y)
 
 HOSTCFLAGS_timestamping.o += -I$(objtree)/usr/include
+HOSTCFLAGS_txtimestamp.o += -I$(objtree)/usr/include
 HOSTCFLAGS_hwtstamp_config.o += -I$(objtree)/usr/include
 
 clean:
-       rm -f timestamping hwtstamp_config
+       rm -f timestamping txtimestamp hwtstamp_config
diff --git a/Documentation/networking/timestamping/txtimestamp.c b/Documentation/networking/timestamping/txtimestamp.c
new file mode 100644 (file)
index 0000000..b32fc2a
--- /dev/null
@@ -0,0 +1,469 @@
+/*
+ * Copyright 2014 Google Inc.
+ * Author: willemb@google.com (Willem de Bruijn)
+ *
+ * Test software tx timestamping, including
+ *
+ * - SCHED, SND and ACK timestamps
+ * - RAW, UDP and TCP
+ * - IPv4 and IPv6
+ * - various packet sizes (to test GSO and TSO)
+ *
+ * Consult the command line arguments for help on running
+ * the various testcases.
+ *
+ * This test requires a dummy TCP server.
+ * A simple `nc6 [-u] -l -p $DESTPORT` will do
+ *
+ *
+ * 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.
+ */
+
+#include <arpa/inet.h>
+#include <asm/types.h>
+#include <error.h>
+#include <errno.h>
+#include <linux/errqueue.h>
+#include <linux/if_ether.h>
+#include <linux/net_tstamp.h>
+#include <netdb.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+#include <netinet/tcp.h>
+#include <netpacket/packet.h>
+#include <poll.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+/* command line parameters */
+static int cfg_proto = SOCK_STREAM;
+static int cfg_ipproto = IPPROTO_TCP;
+static int cfg_num_pkts = 4;
+static int do_ipv4 = 1;
+static int do_ipv6 = 1;
+static int cfg_payload_len = 10;
+static uint16_t dest_port = 9000;
+
+static struct sockaddr_in daddr;
+static struct sockaddr_in6 daddr6;
+static struct timespec ts_prev;
+
+static void __print_timestamp(const char *name, struct timespec *cur,
+                             uint32_t key, int payload_len)
+{
+       if (!(cur->tv_sec | cur->tv_nsec))
+               return;
+
+       fprintf(stderr, "  %s: %lu s %lu us (seq=%u, len=%u)",
+                       name, cur->tv_sec, cur->tv_nsec / 1000,
+                       key, payload_len);
+
+       if ((ts_prev.tv_sec | ts_prev.tv_nsec)) {
+               int64_t cur_ms, prev_ms;
+
+               cur_ms = (long) cur->tv_sec * 1000 * 1000;
+               cur_ms += cur->tv_nsec / 1000;
+
+               prev_ms = (long) ts_prev.tv_sec * 1000 * 1000;
+               prev_ms += ts_prev.tv_nsec / 1000;
+
+               fprintf(stderr, "  (%+ld us)", cur_ms - prev_ms);
+       }
+
+       ts_prev = *cur;
+       fprintf(stderr, "\n");
+}
+
+static void print_timestamp_usr(void)
+{
+       struct timespec ts;
+       struct timeval tv;      /* avoid dependency on -lrt */
+
+       gettimeofday(&tv, NULL);
+       ts.tv_sec = tv.tv_sec;
+       ts.tv_nsec = tv.tv_usec * 1000;
+
+       __print_timestamp("  USR", &ts, 0, 0);
+}
+
+static void print_timestamp(struct scm_timestamping *tss, int tstype,
+                           int tskey, int payload_len)
+{
+       const char *tsname;
+
+       switch (tstype) {
+       case SCM_TSTAMP_SCHED:
+               tsname = "  ENQ";
+               break;
+       case SCM_TSTAMP_SND:
+               tsname = "  SND";
+               break;
+       case SCM_TSTAMP_ACK:
+               tsname = "  ACK";
+               break;
+       default:
+               error(1, 0, "unknown timestamp type: %u",
+               tstype);
+       }
+       __print_timestamp(tsname, &tss->ts[0], tskey, payload_len);
+}
+
+static void __poll(int fd)
+{
+       struct pollfd pollfd;
+       int ret;
+
+       memset(&pollfd, 0, sizeof(pollfd));
+       pollfd.fd = fd;
+       ret = poll(&pollfd, 1, 100);
+       if (ret != 1)
+               error(1, errno, "poll");
+}
+
+static void __recv_errmsg_cmsg(struct msghdr *msg, int payload_len)
+{
+       struct sock_extended_err *serr = NULL;
+       struct scm_timestamping *tss = NULL;
+       struct cmsghdr *cm;
+
+       for (cm = CMSG_FIRSTHDR(msg);
+            cm && cm->cmsg_len;
+            cm = CMSG_NXTHDR(msg, cm)) {
+               if (cm->cmsg_level == SOL_SOCKET &&
+                   cm->cmsg_type == SCM_TIMESTAMPING) {
+                       tss = (void *) CMSG_DATA(cm);
+               } else if ((cm->cmsg_level == SOL_IP &&
+                    cm->cmsg_type == IP_RECVERR) ||
+                   (cm->cmsg_level == SOL_IPV6 &&
+                    cm->cmsg_type == IPV6_RECVERR)) {
+
+                       serr = (void *) CMSG_DATA(cm);
+                       if (serr->ee_errno != ENOMSG ||
+                           serr->ee_origin != SO_EE_ORIGIN_TIMESTAMPING) {
+                               fprintf(stderr, "unknown ip error %d %d\n",
+                                               serr->ee_errno,
+                                               serr->ee_origin);
+                               serr = NULL;
+                       }
+               } else
+                       fprintf(stderr, "unknown cmsg %d,%d\n",
+                                       cm->cmsg_level, cm->cmsg_type);
+       }
+
+       if (serr && tss)
+               print_timestamp(tss, serr->ee_info, serr->ee_data, payload_len);
+}
+
+static int recv_errmsg(int fd)
+{
+       static char ctrl[1024 /* overprovision*/];
+       static struct msghdr msg;
+       struct iovec entry;
+       static char *data;
+       int ret = 0;
+
+       data = malloc(cfg_payload_len);
+       if (!data)
+               error(1, 0, "malloc");
+
+       memset(&msg, 0, sizeof(msg));
+       memset(&entry, 0, sizeof(entry));
+       memset(ctrl, 0, sizeof(ctrl));
+
+       entry.iov_base = data;
+       entry.iov_len = cfg_payload_len;
+       msg.msg_iov = &entry;
+       msg.msg_iovlen = 1;
+       msg.msg_name = NULL;
+       msg.msg_namelen = 0;
+       msg.msg_control = ctrl;
+       msg.msg_controllen = sizeof(ctrl);
+
+       ret = recvmsg(fd, &msg, MSG_ERRQUEUE);
+       if (ret == -1 && errno != EAGAIN)
+               error(1, errno, "recvmsg");
+
+       __recv_errmsg_cmsg(&msg, ret);
+
+       free(data);
+       return ret == -1;
+}
+
+static void do_test(int family, unsigned int opt)
+{
+       char *buf;
+       int fd, i, val, total_len;
+
+       if (family == IPPROTO_IPV6 && cfg_proto != SOCK_STREAM) {
+               /* due to lack of checksum generation code */
+               fprintf(stderr, "test: skipping datagram over IPv6\n");
+               return;
+       }
+
+       total_len = cfg_payload_len;
+       if (cfg_proto == SOCK_RAW) {
+               total_len += sizeof(struct udphdr);
+               if (cfg_ipproto == IPPROTO_RAW)
+                       total_len += sizeof(struct iphdr);
+       }
+
+       buf = malloc(total_len);
+       if (!buf)
+               error(1, 0, "malloc");
+
+       fd = socket(family, cfg_proto, cfg_ipproto);
+       if (fd < 0)
+               error(1, errno, "socket");
+
+       if (cfg_proto == SOCK_STREAM) {
+               val = 1;
+               if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
+                              (char*) &val, sizeof(val)))
+                       error(1, 0, "setsockopt no nagle");
+
+               if (family == PF_INET) {
+                       if (connect(fd, (void *) &daddr, sizeof(daddr)))
+                               error(1, errno, "connect ipv4");
+               } else {
+                       if (connect(fd, (void *) &daddr6, sizeof(daddr6)))
+                               error(1, errno, "connect ipv6");
+               }
+       }
+
+       opt |= SOF_TIMESTAMPING_SOFTWARE |
+              SOF_TIMESTAMPING_OPT_ID;
+       if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING,
+                      (char *) &opt, sizeof(opt)))
+               error(1, 0, "setsockopt timestamping");
+
+       for (i = 0; i < cfg_num_pkts; i++) {
+               memset(&ts_prev, 0, sizeof(ts_prev));
+               memset(buf, 'a' + i, total_len);
+               buf[total_len - 2] = '\n';
+               buf[total_len - 1] = '\0';
+
+               if (cfg_proto == SOCK_RAW) {
+                       struct udphdr *udph;
+                       int off = 0;
+
+                       if (cfg_ipproto == IPPROTO_RAW) {
+                               struct iphdr *iph = (void *) buf;
+
+                               memset(iph, 0, sizeof(*iph));
+                               iph->ihl      = 5;
+                               iph->version  = 4;
+                               iph->ttl      = 2;
+                               iph->daddr    = daddr.sin_addr.s_addr;
+                               iph->protocol = IPPROTO_UDP;
+                               /* kernel writes saddr, csum, len */
+
+                               off = sizeof(*iph);
+                       }
+
+                       udph = (void *) buf + off;
+                       udph->source = ntohs(9000);     /* random spoof */
+                       udph->dest   = ntohs(dest_port);
+                       udph->len    = ntohs(sizeof(*udph) + cfg_payload_len);
+                       udph->check  = 0;       /* not allowed for IPv6 */
+               }
+
+               print_timestamp_usr();
+               if (cfg_proto != SOCK_STREAM) {
+                       if (family == PF_INET)
+                               val = sendto(fd, buf, total_len, 0, (void *) &daddr, sizeof(daddr));
+                       else
+                               val = sendto(fd, buf, total_len, 0, (void *) &daddr6, sizeof(daddr6));
+               } else {
+                       val = send(fd, buf, cfg_payload_len, 0);
+               }
+               if (val != total_len)
+                       error(1, errno, "send");
+
+               /* wait for all errors to be queued, else ACKs arrive OOO */
+               usleep(50 * 1000);
+
+               __poll(fd);
+
+               while (!recv_errmsg(fd)) {}
+       }
+
+       if (close(fd))
+               error(1, errno, "close");
+
+       free(buf);
+       usleep(400 * 1000);
+}
+
+static void __attribute__((noreturn)) usage(const char *filepath)
+{
+       fprintf(stderr, "\nUsage: %s [options] hostname\n"
+                       "\nwhere options are:\n"
+                       "  -4:   only IPv4\n"
+                       "  -6:   only IPv6\n"
+                       "  -h:   show this message\n"
+                       "  -l N: send N bytes at a time\n"
+                       "  -r:   use raw\n"
+                       "  -R:   use raw (IP_HDRINCL)\n"
+                       "  -p N: connect to port N\n"
+                       "  -u:   use udp\n",
+                       filepath);
+       exit(1);
+}
+
+static void parse_opt(int argc, char **argv)
+{
+       int proto_count = 0;
+       char c;
+
+       while ((c = getopt(argc, argv, "46hl:p:rRu")) != -1) {
+               switch (c) {
+               case '4':
+                       do_ipv6 = 0;
+                       break;
+               case '6':
+                       do_ipv4 = 0;
+                       break;
+               case 'r':
+                       proto_count++;
+                       cfg_proto = SOCK_RAW;
+                       cfg_ipproto = IPPROTO_UDP;
+                       break;
+               case 'R':
+                       proto_count++;
+                       cfg_proto = SOCK_RAW;
+                       cfg_ipproto = IPPROTO_RAW;
+                       break;
+               case 'u':
+                       proto_count++;
+                       cfg_proto = SOCK_DGRAM;
+                       cfg_ipproto = IPPROTO_UDP;
+                       break;
+               case 'l':
+                       cfg_payload_len = strtoul(optarg, NULL, 10);
+                       break;
+               case 'p':
+                       dest_port = strtoul(optarg, NULL, 10);
+                       break;
+               case 'h':
+               default:
+                       usage(argv[0]);
+               }
+       }
+
+       if (!cfg_payload_len)
+               error(1, 0, "payload may not be nonzero");
+       if (cfg_proto != SOCK_STREAM && cfg_payload_len > 1472)
+               error(1, 0, "udp packet might exceed expected MTU");
+       if (!do_ipv4 && !do_ipv6)
+               error(1, 0, "pass -4 or -6, not both");
+       if (proto_count > 1)
+               error(1, 0, "pass -r, -R or -u, not multiple");
+
+       if (optind != argc - 1)
+               error(1, 0, "missing required hostname argument");
+}
+
+static void resolve_hostname(const char *hostname)
+{
+       struct addrinfo *addrs, *cur;
+       int have_ipv4 = 0, have_ipv6 = 0;
+
+       if (getaddrinfo(hostname, NULL, NULL, &addrs))
+               error(1, errno, "getaddrinfo");
+
+       cur = addrs;
+       while (cur && !have_ipv4 && !have_ipv6) {
+               if (!have_ipv4 && cur->ai_family == AF_INET) {
+                       memcpy(&daddr, cur->ai_addr, sizeof(daddr));
+                       daddr.sin_port = htons(dest_port);
+                       have_ipv4 = 1;
+               }
+               else if (!have_ipv6 && cur->ai_family == AF_INET6) {
+                       memcpy(&daddr6, cur->ai_addr, sizeof(daddr6));
+                       daddr6.sin6_port = htons(dest_port);
+                       have_ipv6 = 1;
+               }
+               cur = cur->ai_next;
+       }
+       if (addrs)
+               freeaddrinfo(addrs);
+
+       do_ipv4 &= have_ipv4;
+       do_ipv6 &= have_ipv6;
+}
+
+static void do_main(int family)
+{
+       fprintf(stderr, "family:       %s\n",
+                       family == PF_INET ? "INET" : "INET6");
+
+       fprintf(stderr, "test SND\n");
+       do_test(family, SOF_TIMESTAMPING_TX_SOFTWARE);
+
+       fprintf(stderr, "test ENQ\n");
+       do_test(family, SOF_TIMESTAMPING_TX_SCHED);
+
+       fprintf(stderr, "test ENQ + SND\n");
+       do_test(family, SOF_TIMESTAMPING_TX_SCHED |
+                       SOF_TIMESTAMPING_TX_SOFTWARE);
+
+       if (cfg_proto == SOCK_STREAM) {
+               fprintf(stderr, "\ntest ACK\n");
+               do_test(family, SOF_TIMESTAMPING_TX_ACK);
+
+               fprintf(stderr, "\ntest SND + ACK\n");
+               do_test(family, SOF_TIMESTAMPING_TX_SOFTWARE |
+                               SOF_TIMESTAMPING_TX_ACK);
+
+               fprintf(stderr, "\ntest ENQ + SND + ACK\n");
+               do_test(family, SOF_TIMESTAMPING_TX_SCHED |
+                               SOF_TIMESTAMPING_TX_SOFTWARE |
+                               SOF_TIMESTAMPING_TX_ACK);
+       }
+}
+
+const char *sock_names[] = { NULL, "TCP", "UDP", "RAW" };
+
+int main(int argc, char **argv)
+{
+       if (argc == 1)
+               usage(argv[0]);
+
+       parse_opt(argc, argv);
+       resolve_hostname(argv[argc - 1]);
+
+       fprintf(stderr, "protocol:     %s\n", sock_names[cfg_proto]);
+       fprintf(stderr, "payload:      %u\n", cfg_payload_len);
+       fprintf(stderr, "server port:  %u\n", dest_port);
+       fprintf(stderr, "\n");
+
+       if (do_ipv4)
+               do_main(PF_INET);
+       if (do_ipv6)
+               do_main(PF_INET6);
+
+       return 0;
+}
index 81c0e2b49cd86cb9096c72c56d46935677c2d990..8afb236ca7653ed694af2b35e49eadbabd496152 100644 (file)
@@ -143,8 +143,9 @@ This will cause the core to recalculate the total load on the regulator (based
 on all its consumers) and change operating mode (if necessary and permitted)
 to best match the current operating load.
 
-The load_uA value can be determined from the consumers datasheet. e.g.most
-datasheets have tables showing the max current consumed in certain situations.
+The load_uA value can be determined from the consumer's datasheet. e.g. most
+datasheets have tables showing the maximum current consumed in certain
+situations.
 
 Most consumers will use indirect operating mode control since they have no
 knowledge of the regulator or whether the regulator is shared with other
@@ -173,7 +174,7 @@ Consumers can register interest in regulator events by calling :-
 int regulator_register_notifier(struct regulator *regulator,
                              struct notifier_block *nb);
 
-Consumers can uregister interest by calling :-
+Consumers can unregister interest by calling :-
 
 int regulator_unregister_notifier(struct regulator *regulator,
                                struct notifier_block *nb);
index f9b56b72b782f0350dc6e50f12d6fad76edd87cd..fdd919b96830b882e54c31d4c7b1f5f468624a5e 100644 (file)
@@ -9,14 +9,14 @@ Safety
 
  - Errors in regulator configuration can have very serious consequences
    for the system, potentially including lasting hardware damage.
- - It is not possible to automatically determine the power confugration
+ - It is not possible to automatically determine the power configuration
    of the system - software-equivalent variants of the same chip may
-   have different power requirments, and not all components with power
+   have different power requirements, and not all components with power
    requirements are visible to software.
 
   => The API should make no changes to the hardware state unless it has
-     specific knowledge that these changes are safe to do perform on
-     this particular system.
+     specific knowledge that these changes are safe to perform on this
+     particular system.
 
 Consumer use cases
 ------------------
index ce63af0a8e35ecab32e2f326d13a9a2b33b62909..757e3b53dc11a8acbb4d048487caab90b0ea8ebd 100644 (file)
@@ -11,7 +11,7 @@ Consider the following machine :-
                +-> [Consumer B @ 3.3V]
 
 The drivers for consumers A & B must be mapped to the correct regulator in
-order to control their power supply. This mapping can be achieved in machine
+order to control their power supplies. This mapping can be achieved in machine
 initialisation code by creating a struct regulator_consumer_supply for
 each regulator.
 
@@ -39,7 +39,7 @@ to the 'Vcc' supply for Consumer A.
 
 Constraints can now be registered by defining a struct regulator_init_data
 for each regulator power domain. This structure also maps the consumers
-to their supply regulator :-
+to their supply regulators :-
 
 static struct regulator_init_data regulator1_data = {
        .constraints = {
index 8ed17587a74bdc006b2d2922b5709f0e16ec08ad..40ca2d6e2742d182933443012aad9f6157eac361 100644 (file)
@@ -36,11 +36,11 @@ Some terms used in this document:-
                    Consumers can be classified into two types:-
 
                    Static: consumer does not change its supply voltage or
-                   current limit. It only needs to enable or disable it's
+                   current limit. It only needs to enable or disable its
                    power supply. Its supply voltage is set by the hardware,
                    bootloader, firmware or kernel board initialisation code.
 
-                   Dynamic: consumer needs to change it's supply voltage or
+                   Dynamic: consumer needs to change its supply voltage or
                    current limit to meet operation demands.
 
 
@@ -156,7 +156,7 @@ relevant to non SoC devices and is split into the following four interfaces:-
       This interface is for machine specific code and allows the creation of
       voltage/current domains (with constraints) for each regulator. It can
       provide regulator constraints that will prevent device damage through
-      overvoltage or over current caused by buggy client drivers. It also
+      overvoltage or overcurrent caused by buggy client drivers. It also
       allows the creation of a regulator tree whereby some regulators are
       supplied by others (similar to a clock tree).
 
index 13902778ae44ceb31f4f0c1c5dc173f63ffd9b8a..b17e5833ce214f963ed9af87f6f7fcf0e2c5ac18 100644 (file)
@@ -13,7 +13,7 @@ Drivers can register a regulator by calling :-
 struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
                                         const struct regulator_config *config);
 
-This will register the regulators capabilities and operations to the regulator
+This will register the regulator's capabilities and operations to the regulator
 core.
 
 Regulators can be unregistered by calling :-
@@ -23,8 +23,8 @@ void regulator_unregister(struct regulator_dev *rdev);
 
 Regulator Events
 ================
-Regulators can send events (e.g. over temp, under voltage, etc) to consumer
-drivers by calling :-
+Regulators can send events (e.g. overtemperature, undervoltage, etc) to
+consumer drivers by calling :-
 
 int regulator_notifier_call_chain(struct regulator_dev *rdev,
                                  unsigned long event, void *data);
index 9a0319a8247032c0fb6ae1a34129eacbba40c5eb..04892b821157774b81f4adecae870e06ef6f9bd4 100644 (file)
@@ -241,6 +241,9 @@ address of the router (or Connected) for internal networks.
 6. TIPC
 -------------------------------------------------------
 
+tipc_rmem
+----------
+
 The TIPC protocol now has a tunable for the receive memory, similar to the
 tcp_rmem - i.e. a vector of 3 INTEGERs: (min, default, max)
 
@@ -252,3 +255,16 @@ The max value is set to CONN_OVERLOAD_LIMIT, and the default and min values
 are scaled (shifted) versions of that same value.  Note that the min value
 is not at this point in time used in any meaningful way, but the triplet is
 preserved in order to be consistent with things like tcp_rmem.
+
+named_timeout
+--------------
+
+TIPC name table updates are distributed asynchronously in a cluster, without
+any form of transaction handling. This means that different race scenarios are
+possible. One such is that a name withdrawal sent out by one node and received
+by another node may arrive after a second, overlapping name publication already
+has been accepted from a third node, although the conflicting updates
+originally may have been issued in the correct sequential order.
+If named_timeout is nonzero, failed topology updates will be placed on a defer
+queue until another event arrives that clears the error, or until the timeout
+expires. Value is in milliseconds.
index 1a4ce7e3e05f4836d6219838fc263440611e621d..0ec995712176ed83d4dd04ecfed81aa442848c07 100644 (file)
@@ -2,26 +2,26 @@ this_cpu operations
 -------------------
 
 this_cpu operations are a way of optimizing access to per cpu
-variables associated with the *currently* executing processor through
-the use of segment registers (or a dedicated register where the cpu
-permanently stored the beginning of the per cpu area for a specific
-processor).
+variables associated with the *currently* executing processor. This is
+done through the use of segment registers (or a dedicated register where
+the cpu permanently stored the beginning of the per cpu        area for a
+specific processor).
 
-The this_cpu operations add a per cpu variable offset to the processor
-specific percpu base and encode that operation in the instruction
+this_cpu operations add a per cpu variable offset to the processor
+specific per cpu base and encode that operation in the instruction
 operating on the per cpu variable.
 
-This means there are no atomicity issues between the calculation of
+This means that there are no atomicity issues between the calculation of
 the offset and the operation on the data. Therefore it is not
-necessary to disable preempt or interrupts to ensure that the
+necessary to disable preemption or interrupts to ensure that the
 processor is not changed between the calculation of the address and
 the operation on the data.
 
 Read-modify-write operations are of particular interest. Frequently
 processors have special lower latency instructions that can operate
-without the typical synchronization overhead but still provide some
-sort of relaxed atomicity guarantee. The x86 for example can execute
-RMV (Read Modify Write) instructions like inc/dec/cmpxchg without the
+without the typical synchronization overhead, but still provide some
+sort of relaxed atomicity guarantees. The x86, for example, can execute
+RMW (Read Modify Write) instructions like inc/dec/cmpxchg without the
 lock prefix and the associated latency penalty.
 
 Access to the variable without the lock prefix is not synchronized but
@@ -30,6 +30,38 @@ data specific to the currently executing processor. Only the current
 processor should be accessing that variable and therefore there are no
 concurrency issues with other processors in the system.
 
+Please note that accesses by remote processors to a per cpu area are
+exceptional situations and may impact performance and/or correctness
+(remote write operations) of local RMW operations via this_cpu_*.
+
+The main use of the this_cpu operations has been to optimize counter
+operations.
+
+The following this_cpu() operations with implied preemption protection
+are defined. These operations can be used without worrying about
+preemption and interrupts.
+
+       this_cpu_add()
+       this_cpu_read(pcp)
+       this_cpu_write(pcp, val)
+       this_cpu_add(pcp, val)
+       this_cpu_and(pcp, val)
+       this_cpu_or(pcp, val)
+       this_cpu_add_return(pcp, val)
+       this_cpu_xchg(pcp, nval)
+       this_cpu_cmpxchg(pcp, oval, nval)
+       this_cpu_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2)
+       this_cpu_sub(pcp, val)
+       this_cpu_inc(pcp)
+       this_cpu_dec(pcp)
+       this_cpu_sub_return(pcp, val)
+       this_cpu_inc_return(pcp)
+       this_cpu_dec_return(pcp)
+
+
+Inner working of this_cpu operations
+------------------------------------
+
 On x86 the fs: or the gs: segment registers contain the base of the
 per cpu area. It is then possible to simply use the segment override
 to relocate a per cpu relative address to the proper per cpu area for
@@ -48,22 +80,21 @@ results in a single instruction
        mov ax, gs:[x]
 
 instead of a sequence of calculation of the address and then a fetch
-from that address which occurs with the percpu operations. Before
+from that address which occurs with the per cpu operations. Before
 this_cpu_ops such sequence also required preempt disable/enable to
 prevent the kernel from moving the thread to a different processor
 while the calculation is performed.
 
-The main use of the this_cpu operations has been to optimize counter
-operations.
+Consider the following this_cpu operation:
 
        this_cpu_inc(x)
 
-results in the following single instruction (no lock prefix!)
+The above results in the following single instruction (no lock prefix!)
 
        inc gs:[x]
 
 instead of the following operations required if there is no segment
-register.
+register:
 
        int *y;
        int cpu;
@@ -73,10 +104,10 @@ register.
        (*y)++;
        put_cpu();
 
-Note that these operations can only be used on percpu data that is
+Note that these operations can only be used on per cpu data that is
 reserved for a specific processor. Without disabling preemption in the
 surrounding code this_cpu_inc() will only guarantee that one of the
-percpu counters is correctly incremented. However, there is no
+per cpu counters is correctly incremented. However, there is no
 guarantee that the OS will not move the process directly before or
 after the this_cpu instruction is executed. In general this means that
 the value of the individual counters for each processor are
@@ -86,9 +117,9 @@ that is of interest.
 Per cpu variables are used for performance reasons. Bouncing cache
 lines can be avoided if multiple processors concurrently go through
 the same code paths.  Since each processor has its own per cpu
-variables no concurrent cacheline updates take place. The price that
+variables no concurrent cache line updates take place. The price that
 has to be paid for this optimization is the need to add up the per cpu
-counters when the value of the counter is needed.
+counters when the value of a counter is needed.
 
 
 Special operations:
@@ -100,33 +131,39 @@ Takes the offset of a per cpu variable (&x !) and returns the address
 of the per cpu variable that belongs to the currently executing
 processor.  this_cpu_ptr avoids multiple steps that the common
 get_cpu/put_cpu sequence requires. No processor number is
-available. Instead the offset of the local per cpu area is simply
-added to the percpu offset.
+available. Instead, the offset of the local per cpu area is simply
+added to the per cpu offset.
 
+Note that this operation is usually used in a code segment when
+preemption has been disabled. The pointer is then used to
+access local per cpu data in a critical section. When preemption
+is re-enabled this pointer is usually no longer useful since it may
+no longer point to per cpu data of the current processor.
 
 
 Per cpu variables and offsets
 -----------------------------
 
-Per cpu variables have *offsets* to the beginning of the percpu
+Per cpu variables have *offsets* to the beginning of the per cpu
 area. They do not have addresses although they look like that in the
 code. Offsets cannot be directly dereferenced. The offset must be
-added to a base pointer of a percpu area of a processor in order to
+added to a base pointer of a per cpu area of a processor in order to
 form a valid address.
 
 Therefore the use of x or &x outside of the context of per cpu
 operations is invalid and will generally be treated like a NULL
 pointer dereference.
 
-In the context of per cpu operations
+       DEFINE_PER_CPU(int, x);
 
-       x is a per cpu variable. Most this_cpu operations take a cpu
-       variable.
+In the context of per cpu operations the above implies that x is a per
+cpu variable. Most this_cpu operations take a cpu variable.
 
-       &x is the *offset* a per cpu variable. this_cpu_ptr() takes
-       the offset of a per cpu variable which makes this look a bit
-       strange.
+       int __percpu *p = &x;
 
+&x and hence p is the *offset* of a per cpu variable. this_cpu_ptr()
+takes the offset of a per cpu variable which makes this look a bit
+strange.
 
 
 Operations on a field of a per cpu structure
@@ -152,7 +189,7 @@ If we have an offset to struct s:
 
        struct s __percpu *ps = &p;
 
-       z = this_cpu_dec(ps->m);
+       this_cpu_dec(ps->m);
 
        z = this_cpu_inc_return(ps->n);
 
@@ -172,29 +209,52 @@ if we do not make use of this_cpu ops later to manipulate fields:
 Variants of this_cpu ops
 -------------------------
 
-this_cpu ops are interrupt safe. Some architecture do not support
+this_cpu ops are interrupt safe. Some architectures do not support
 these per cpu local operations. In that case the operation must be
 replaced by code that disables interrupts, then does the operations
-that are guaranteed to be atomic and then reenable interrupts. Doing
+that are guaranteed to be atomic and then re-enable interrupts. Doing
 so is expensive. If there are other reasons why the scheduler cannot
 change the processor we are executing on then there is no reason to
-disable interrupts. For that purpose the __this_cpu operations are
-provided. For example.
-
-       __this_cpu_inc(x);
-
-Will increment x and will not fallback to code that disables
+disable interrupts. For that purpose the following __this_cpu operations
+are provided.
+
+These operations have no guarantee against concurrent interrupts or
+preemption. If a per cpu variable is not used in an interrupt context
+and the scheduler cannot preempt, then they are safe. If any interrupts
+still occur while an operation is in progress and if the interrupt too
+modifies the variable, then RMW actions can not be guaranteed to be
+safe.
+
+       __this_cpu_add()
+       __this_cpu_read(pcp)
+       __this_cpu_write(pcp, val)
+       __this_cpu_add(pcp, val)
+       __this_cpu_and(pcp, val)
+       __this_cpu_or(pcp, val)
+       __this_cpu_add_return(pcp, val)
+       __this_cpu_xchg(pcp, nval)
+       __this_cpu_cmpxchg(pcp, oval, nval)
+       __this_cpu_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2)
+       __this_cpu_sub(pcp, val)
+       __this_cpu_inc(pcp)
+       __this_cpu_dec(pcp)
+       __this_cpu_sub_return(pcp, val)
+       __this_cpu_inc_return(pcp)
+       __this_cpu_dec_return(pcp)
+
+
+Will increment x and will not fall-back to code that disables
 interrupts on platforms that cannot accomplish atomicity through
 address relocation and a Read-Modify-Write operation in the same
 instruction.
 
 
-
 &this_cpu_ptr(pp)->n vs this_cpu_ptr(&pp->n)
 --------------------------------------------
 
 The first operation takes the offset and forms an address and then
-adds the offset of the n field.
+adds the offset of the n field. This may result in two add
+instructions emitted by the compiler.
 
 The second one first adds the two offsets and then does the
 relocation.  IMHO the second form looks cleaner and has an easier time
@@ -202,4 +262,73 @@ with (). The second form also is consistent with the way
 this_cpu_read() and friends are used.
 
 
-Christoph Lameter, April 3rd, 2013
+Remote access to per cpu data
+------------------------------
+
+Per cpu data structures are designed to be used by one cpu exclusively.
+If you use the variables as intended, this_cpu_ops() are guaranteed to
+be "atomic" as no other CPU has access to these data structures.
+
+There are special cases where you might need to access per cpu data
+structures remotely. It is usually safe to do a remote read access
+and that is frequently done to summarize counters. Remote write access
+something which could be problematic because this_cpu ops do not
+have lock semantics. A remote write may interfere with a this_cpu
+RMW operation.
+
+Remote write accesses to percpu data structures are highly discouraged
+unless absolutely necessary. Please consider using an IPI to wake up
+the remote CPU and perform the update to its per cpu area.
+
+To access per-cpu data structure remotely, typically the per_cpu_ptr()
+function is used:
+
+
+       DEFINE_PER_CPU(struct data, datap);
+
+       struct data *p = per_cpu_ptr(&datap, cpu);
+
+This makes it explicit that we are getting ready to access a percpu
+area remotely.
+
+You can also do the following to convert the datap offset to an address
+
+       struct data *p = this_cpu_ptr(&datap);
+
+but, passing of pointers calculated via this_cpu_ptr to other cpus is
+unusual and should be avoided.
+
+Remote access are typically only for reading the status of another cpus
+per cpu data. Write accesses can cause unique problems due to the
+relaxed synchronization requirements for this_cpu operations.
+
+One example that illustrates some concerns with write operations is
+the following scenario that occurs because two per cpu variables
+share a cache-line but the relaxed synchronization is applied to
+only one process updating the cache-line.
+
+Consider the following example
+
+
+       struct test {
+               atomic_t a;
+               int b;
+       };
+
+       DEFINE_PER_CPU(struct test, onecacheline);
+
+There is some concern about what would happen if the field 'a' is updated
+remotely from one processor and the local processor would use this_cpu ops
+to update field b. Care should be taken that such simultaneous accesses to
+data within the same cache line are avoided. Also costly synchronization
+may be necessary. IPIs are generally recommended in such scenarios instead
+of a remote write to the per cpu area of another processor.
+
+Even in cases where the remote writes are rare, please bear in
+mind that a remote write will evict the cache line from the processor
+that most likely will access it. If the processor wakes up and finds a
+missing local cache line of a per cpu area, its performance and hence
+the wake up times will be affected.
+
+Christoph Lameter, August 4th, 2014
+Pranith Kumar, Aug 2nd, 2014
index 2b3a82e69151419239e8b6b8adb29095beb8c423..39d1723267036a5ba7dff02dc82e39d69a1eeae8 100644 (file)
@@ -35,7 +35,7 @@ invlpg instruction (or instructions _near_ it) show up high in
 profiles.  If you believe that individual invalidations being
 called too often, you can lower the tunable:
 
-       /sys/debug/kernel/x86/tlb_single_page_flush_ceiling
+       /sys/kernel/debug/x86/tlb_single_page_flush_ceiling
 
 This will cause us to do the global flush for more cases.
 Lowering it to 0 will disable the use of the individual flushes.
index 2f85f55c8fb860779801ba88a144bd2c4a6c1477..5e3709ebc23465d506f9c914d4ba372a7f2104f0 100644 (file)
@@ -152,8 +152,8 @@ F:  drivers/scsi/53c700*
 
 6LOWPAN GENERIC (BTLE/IEEE 802.15.4)
 M:     Alexander Aring <alex.aring@gmail.com>
-L:     linux-zigbee-devel@lists.sourceforge.net (moderated for non-subscribers)
 L:     linux-bluetooth@vger.kernel.org
+L:     linux-wpan@vger.kernel.org
 S:     Maintained
 F:     net/6lowpan/
 F:     include/net/6lowpan.h
@@ -1277,9 +1277,15 @@ F:       drivers/scsi/arm/
 ARM/Rockchip SoC support
 M:     Heiko Stuebner <heiko@sntech.de>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+L:     linux-rockchip@lists.infradead.org
 S:     Maintained
+F:     arch/arm/boot/dts/rk3*
 F:     arch/arm/mach-rockchip/
+F:     drivers/clk/rockchip/
+F:     drivers/i2c/busses/i2c-rk3x.c
 F:     drivers/*/*rockchip*
+F:     drivers/*/*/*rockchip*
+F:     sound/soc/rockchip/
 
 ARM/SAMSUNG ARM ARCHITECTURES
 M:     Ben Dooks <ben-linux@fluff.org>
@@ -1843,6 +1849,12 @@ S:       Orphan
 F:     Documentation/filesystems/befs.txt
 F:     fs/befs/
 
+BECKHOFF CX5020 ETHERCAT MASTER DRIVER
+M: Dariusz Marcinkiewicz <reksio@newterm.pl>
+L: netdev@vger.kernel.org
+S: Maintained
+F: drivers/net/ethernet/ec_bhf.c
+
 BFS FILE SYSTEM
 M:     "Tigran A. Aivazian" <tigran@aivazian.fsnet.co.uk>
 S:     Maintained
@@ -2059,7 +2071,7 @@ S:        Supported
 F:     drivers/scsi/bnx2i/
 
 BROADCOM KONA GPIO DRIVER
-M:     Markus Mayer <markus.mayer@linaro.org>
+M:     Ray Jui <rjui@broadcom.com>
 L:     bcm-kernel-feedback-list@broadcom.com
 S:     Supported
 F:     drivers/gpio/gpio-bcm-kona.c
@@ -3115,6 +3127,17 @@ F:       include/linux/host1x.h
 F:     include/uapi/drm/tegra_drm.h
 F:     Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt
 
+DRM DRIVERS FOR RENESAS
+M:     Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+L:     dri-devel@lists.freedesktop.org
+L:     linux-sh@vger.kernel.org
+T:     git git://people.freedesktop.org/~airlied/linux
+S:     Supported
+F:     drivers/gpu/drm/rcar-du/
+F:     drivers/gpu/drm/shmobile/
+F:     include/linux/platform_data/rcar-du.h
+F:     include/linux/platform_data/shmob_drm.h
+
 DSBR100 USB FM RADIO DRIVER
 M:     Alexey Klimov <klimov.linux@gmail.com>
 L:     linux-media@vger.kernel.org
@@ -3843,10 +3866,13 @@ F:      drivers/tty/serial/ucc_uart.c
 
 FREESCALE SOC SOUND DRIVERS
 M:     Timur Tabi <timur@tabi.org>
+M:     Nicolin Chen <nicoleotsuka@gmail.com>
+M:     Xiubo Li <Li.Xiubo@freescale.com>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 L:     linuxppc-dev@lists.ozlabs.org
 S:     Maintained
 F:     sound/soc/fsl/fsl*
+F:     sound/soc/fsl/imx*
 F:     sound/soc/fsl/mpc8610_hpcd.c
 
 FREEVXFS FILESYSTEM
@@ -4446,6 +4472,13 @@ F:       include/linux/i2c-*.h
 F:     include/uapi/linux/i2c.h
 F:     include/uapi/linux/i2c-*.h
 
+I2C ACPI SUPPORT
+M:     Mika Westerberg <mika.westerberg@linux.intel.com>
+L:     linux-i2c@vger.kernel.org
+L:     linux-acpi@vger.kernel.org
+S:     Maintained
+F:     drivers/i2c/i2c-acpi.c
+
 I2C-TAOS-EVM DRIVER
 M:     Jean Delvare <jdelvare@suse.de>
 L:     linux-i2c@vger.kernel.org
@@ -4564,13 +4597,14 @@ F:      drivers/idle/i7300_idle.c
 
 IEEE 802.15.4 SUBSYSTEM
 M:     Alexander Aring <alex.aring@gmail.com>
-L:     linux-zigbee-devel@lists.sourceforge.net (moderated for non-subscribers)
-W:     http://apps.sourceforge.net/trac/linux-zigbee
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lowpan/lowpan.git
+L:     linux-wpan@vger.kernel.org
+W:     https://github.com/linux-wpan
+T:     git git://github.com/linux-wpan/linux-wpan-next.git
 S:     Maintained
 F:     net/ieee802154/
 F:     net/mac802154/
 F:     drivers/net/ieee802154/
+F:     Documentation/networking/ieee802154.txt
 
 IGUANAWORKS USB IR TRANSCEIVER
 M:     Sean Young <sean@mess.org>
@@ -5972,6 +6006,12 @@ T:       git git://linuxtv.org/media_tree.git
 S:     Maintained
 F:     drivers/media/radio/radio-mr800.c
 
+MRF24J40 IEEE 802.15.4 RADIO DRIVER
+M:     Alan Ott <alan@signal11.us>
+L:     linux-wpan@vger.kernel.org
+S:     Maintained
+F:     drivers/net/ieee802154/mrf24j40.c
+
 MSI LAPTOP SUPPORT
 M:     "Lee, Chun-Yi" <jlee@suse.com>
 L:     platform-driver-x86@vger.kernel.org
@@ -6334,7 +6374,7 @@ M:        Lauro Ramos Venancio <lauro.venancio@openbossa.org>
 M:     Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
 M:     Samuel Ortiz <sameo@linux.intel.com>
 L:     linux-wireless@vger.kernel.org
-L:     linux-nfc@lists.01.org (moderated for non-subscribers)
+L:     linux-nfc@lists.01.org (subscribers-only)
 S:     Supported
 F:     net/nfc/
 F:     include/net/nfc/
@@ -6858,6 +6898,14 @@ S:       Supported
 F:     Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt
 F:     drivers/pci/host/pci-tegra.c
 
+PCI DRIVER FOR TI DRA7XX
+M:     Kishon Vijay Abraham I <kishon@ti.com>
+L:     linux-omap@vger.kernel.org
+L:     linux-pci@vger.kernel.org
+S:     Supported
+F:     Documentation/devicetree/bindings/pci/ti-pci.txt
+F:     drivers/pci/host/pci-dra7xx.c
+
 PCI DRIVER FOR RENESAS R-CAR
 M:     Simon Horman <horms@verge.net.au>
 L:     linux-pci@vger.kernel.org
@@ -7059,6 +7107,7 @@ F:        drivers/scsi/pmcraid.*
 PMC SIERRA PM8001 DRIVER
 M:     xjtuwjp@gmail.com
 M:     lindar_liu@usish.com
+L:     pmchba@pmcs.com
 L:     linux-scsi@vger.kernel.org
 S:     Supported
 F:     drivers/scsi/pm8001/
@@ -7330,7 +7379,7 @@ F:        drivers/net/ethernet/qlogic/qla3xxx.*
 
 QLOGIC QLCNIC (1/10)Gb ETHERNET DRIVER
 M:     Shahed Shaikh <shahed.shaikh@qlogic.com>
-M:     Dept-HSGLinuxNICDev@qlogic.com
+M:     Dept-GELinuxNICDev@qlogic.com
 L:     netdev@vger.kernel.org
 S:     Supported
 F:     drivers/net/ethernet/qlogic/qlcnic/
@@ -9514,6 +9563,14 @@ S:       Maintained
 F:     Documentation/usb/ohci.txt
 F:     drivers/usb/host/ohci*
 
+USB OVER IP DRIVER
+M:     Valentina Manea <valentina.manea.m@gmail.com>
+M:     Shuah Khan <shuah.kh@samsung.com>
+L:     linux-usb@vger.kernel.org
+S:     Maintained
+F:     drivers/usb/usbip/
+F:     tools/usb/usbip/
+
 USB PEGASUS DRIVER
 M:     Petko Manolov <petkan@nucleusys.com>
 L:     linux-usb@vger.kernel.org
@@ -10014,9 +10071,9 @@ F:      Documentation/x86/
 F:     arch/x86/
 
 X86 PLATFORM DRIVERS
-M:     Matthew Garrett <matthew.garrett@nebula.com>
+M:     Darren Hart <dvhart@infradead.org>
 L:     platform-driver-x86@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mjg59/platform-drivers-x86.git
+T:     git git://git.infradead.org/users/dvhart/linux-platform-drivers-x86.git
 S:     Maintained
 F:     drivers/platform/x86/
 
index 6aace6750567ba113388cdf43312d3a46d011c1b..1a60bdd05c9a1611f3cee75f1073354d5a6297d0 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 3
-PATCHLEVEL = 16
+PATCHLEVEL = 17
 SUBLEVEL = 0
-EXTRAVERSION =
+EXTRAVERSION = -rc4
 NAME = Shuffling Zombie Juror
 
 # *DOCUMENTATION*
index 5ebab5895edb7991e660104d8288514d77fdf2c3..f05bdb4b1cb97ee8f0d3bbec58fbc7285522c852 100644 (file)
@@ -500,10 +500,14 @@ extern inline void writeq(u64 b, volatile void __iomem *addr)
 #define outb_p         outb
 #define outw_p         outw
 #define outl_p         outl
-#define readb_relaxed(addr) __raw_readb(addr)
-#define readw_relaxed(addr) __raw_readw(addr)
-#define readl_relaxed(addr) __raw_readl(addr)
-#define readq_relaxed(addr) __raw_readq(addr)
+#define readb_relaxed(addr)    __raw_readb(addr)
+#define readw_relaxed(addr)    __raw_readw(addr)
+#define readl_relaxed(addr)    __raw_readl(addr)
+#define readq_relaxed(addr)    __raw_readq(addr)
+#define writeb_relaxed(b, addr)        __raw_writeb(b, addr)
+#define writew_relaxed(b, addr)        __raw_writew(b, addr)
+#define writel_relaxed(b, addr)        __raw_writel(b, addr)
+#define writeq_relaxed(b, addr)        __raw_writeq(b, addr)
 
 #define mmiowb()
 
index f2c94402e2c8b95028bace631c3cbf6f2aeca5b1..c509d306db4561ea65a40703b42e7f9bd078d352 100644 (file)
@@ -3,7 +3,7 @@
 
 #include <uapi/asm/unistd.h>
 
-#define NR_SYSCALLS                    508
+#define NR_SYSCALLS                    511
 
 #define __ARCH_WANT_OLD_READDIR
 #define __ARCH_WANT_STAT64
index 53ae7bb1bfd1b3841572ae69587b80dddd9c0657..d214a0358100b6ad82a63fce68bc6016eb9ddaa4 100644 (file)
 #define __NR_process_vm_writev         505
 #define __NR_kcmp                      506
 #define __NR_finit_module              507
+#define __NR_sched_setattr             508
+#define __NR_sched_getattr             509
+#define __NR_renameat2                 510
 
 #endif /* _UAPI_ALPHA_UNISTD_H */
index dca9b3fb0071d8c24c1c5e1048a0da8461e12d8e..24789713f1eafb4757ec1084c32225ce88bf4ad4 100644 (file)
@@ -526,6 +526,9 @@ sys_call_table:
        .quad sys_process_vm_writev             /* 505 */
        .quad sys_kcmp
        .quad sys_finit_module
+       .quad sys_sched_setattr
+       .quad sys_sched_getattr
+       .quad sys_renameat2                     /* 510 */
 
        .size sys_call_table, . - sys_call_table
        .type sys_call_table, @object
index 4670afc3b971374886c923efc762ed2684b9aa49..9e1142729fd14c003c4f302a8305de1d735ab7a2 100644 (file)
@@ -427,7 +427,7 @@ struct ic_inv_args {
 
 static void __ic_line_inv_vaddr_helper(void *info)
 {
-        struct ic_inv *ic_inv_args = (struct ic_inv_args *) info;
+        struct ic_inv_args *ic_inv = info;
 
         __ic_line_inv_vaddr_local(ic_inv->paddr, ic_inv->vaddr, ic_inv->sz);
 }
@@ -581,6 +581,7 @@ void flush_icache_range(unsigned long kstart, unsigned long kend)
                tot_sz -= sz;
        }
 }
+EXPORT_SYMBOL(flush_icache_range);
 
 /*
  * General purpose helper to make I and D cache lines consistent.
index c49a775937db39912411a33be3d63a5d31eacfba..32cbbd5659023cffe04faf6c97eb7ee5be196585 100644 (file)
@@ -1983,8 +1983,6 @@ config XIP_PHYS_ADDR
 config KEXEC
        bool "Kexec system call (EXPERIMENTAL)"
        depends on (!SMP || PM_SLEEP_SMP)
-       select CRYPTO
-       select CRYPTO_SHA256
        help
          kexec is a system call that implements the ability to shutdown your
          current kernel, and to start another kernel.  It is like a reboot
index 9b3d2ba82f13a1b6aaf725c0e529255310726052..8689949bdba3f7fad944beaf77ce9b5efa6dbe59 100644 (file)
 
                        usb1: usb@48390000 {
                                compatible = "synopsys,dwc3";
-                               reg = <0x48390000 0x17000>;
+                               reg = <0x48390000 0x10000>;
                                interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
                                phys = <&usb2_phy1>;
                                phy-names = "usb2-phy";
 
                        usb2: usb@483d0000 {
                                compatible = "synopsys,dwc3";
-                               reg = <0x483d0000 0x17000>;
+                               reg = <0x483d0000 0x10000>;
                                interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>;
                                phys = <&usb2_phy2>;
                                phy-names = "usb2-phy";
index 646a6eade788f0114847bfa254f9bb7fcff272be..e7ac47fa6615e33ee52e3ef58025721f49c7eb08 100644 (file)
        status = "okay";
        pinctrl-names = "default";
        pinctrl-0 = <&i2c0_pins>;
-       clock-frequency = <400000>;
+       clock-frequency = <100000>;
 
        tps65218: tps65218@24 {
                reg = <0x24>;
        ranges = <0 0 0 0x01000000>;    /* minimum GPMC partition = 16MB */
        nand@0,0 {
                reg = <0 0 4>;          /* device IO registers */
-               ti,nand-ecc-opt = "bch8";
+               ti,nand-ecc-opt = "bch16";
                ti,elm-id = <&elm>;
                nand-bus-width = <8>;
                gpmc,device-width = <1>;
                gpmc,rd-cycle-ns = <40>;
                gpmc,wr-cycle-ns = <40>;
                gpmc,wait-pin = <0>;
-               gpmc,wait-on-read;
-               gpmc,wait-on-write;
                gpmc,bus-turnaround-ns = <0>;
                gpmc,cycle2cycle-delay-ns = <0>;
                gpmc,clk-activation-ns = <0>;
index ed7dd23959155598aba377c27d727e8dc481c551..ac3e4859935f1ad31da67107eda970eec6f526ba 100644 (file)
 };
 
 &gpmc {
-       status = "okay";
+       status = "okay";        /* Disable QSPI when enabling GPMC (NAND) */
        pinctrl-names = "default";
        pinctrl-0 = <&nand_flash_x8>;
        ranges = <0 0 0x08000000 0x10000000>;   /* CS0: NAND */
        nand@0,0 {
                reg = <0 0 0>; /* CS0, offset 0 */
-               ti,nand-ecc-opt = "bch8";
+               ti,nand-ecc-opt = "bch16";
                ti,elm-id = <&elm>;
                nand-bus-width = <8>;
                gpmc,device-width = <1>;
                gpmc,access-ns = <30>; /* tCEA + 4*/
                gpmc,rd-cycle-ns = <40>;
                gpmc,wr-cycle-ns = <40>;
-               gpmc,wait-on-read = "true";
-               gpmc,wait-on-write = "true";
+               gpmc,wait-pin = <0>;
                gpmc,bus-turnaround-ns = <0>;
                gpmc,cycle2cycle-delay-ns = <0>;
                gpmc,clk-activation-ns = <0>;
 };
 
 &qspi {
-       status = "okay";
+       status = "disabled";    /* Disable GPMC (NAND) when enabling QSPI */
        pinctrl-names = "default";
        pinctrl-0 = <&qspi1_default>;
 
index 65ccf564b9a5636eabb7af6cf2697d5c28dccd74..6c97d4af61eec9e36da60ab3257c508e0ef3ba7e 100644 (file)
                                usb: usbck {
                                        compatible = "atmel,at91rm9200-clk-usb";
                                        #clock-cells = <0>;
-                                       atmel,clk-divisors = <1 2>;
+                                       atmel,clk-divisors = <1 2 0 0>;
                                        clocks = <&pllb>;
                                };
 
index 31f7652612fc8f2f1e284b74eb6f9bef7e8e7986..4e0abbd9d6553e71d6881b074196d62dea4ac04b 100644 (file)
@@ -40,6 +40,7 @@
                                };
 
                                pllb: pllbck {
+                                       compatible = "atmel,at91sam9g20-clk-pllb";
                                        atmel,clk-input-range = <2000000 32000000>;
                                        atmel,pll-clk-output-ranges = <30000000 100000000 0 0>;
                                };
index 50f8022905a1f36e415f93f8638055993d5f4b5d..e03fbf3c6889120e9fce89d0fdb39fb70fe7b222 100644 (file)
@@ -8,6 +8,7 @@
 /dts-v1/;
 
 #include "dra74x.dtsi"
+#include <dt-bindings/gpio/gpio.h>
 
 / {
        model = "TI DRA742";
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
        };
+
+       vtt_fixed: fixedregulator-vtt {
+               compatible = "regulator-fixed";
+               regulator-name = "vtt_fixed";
+               regulator-min-microvolt = <1350000>;
+               regulator-max-microvolt = <1350000>;
+               regulator-always-on;
+               regulator-boot-on;
+               enable-active-high;
+               gpio = <&gpio7 11 GPIO_ACTIVE_HIGH>;
+       };
 };
 
 &dra7_pmx_core {
+       pinctrl-names = "default";
+       pinctrl-0 = <&vtt_pin>;
+
+       vtt_pin: pinmux_vtt_pin {
+               pinctrl-single,pins = <
+                       0x3b4 (PIN_OUTPUT | MUX_MODE14) /* spi1_cs1.gpio7_11 */
+               >;
+       };
+
        i2c1_pins: pinmux_i2c1_pins {
                pinctrl-single,pins = <
                        0x400 (PIN_INPUT | MUX_MODE0) /* i2c1_sda */
 
        i2c3_pins: pinmux_i2c3_pins {
                pinctrl-single,pins = <
-                       0x410 (PIN_INPUT | MUX_MODE0) /* i2c3_sda */
-                       0x414 (PIN_INPUT | MUX_MODE0) /* i2c3_scl */
+                       0x288 (PIN_INPUT | MUX_MODE9) /* gpio6_14.i2c3_sda */
+                       0x28c (PIN_INPUT | MUX_MODE9) /* gpio6_15.i2c3_scl */
                >;
        };
 
        mcspi1_pins: pinmux_mcspi1_pins {
                pinctrl-single,pins = <
-                       0x3a4 (PIN_INPUT | MUX_MODE0) /* spi2_clk */
-                       0x3a8 (PIN_INPUT | MUX_MODE0) /* spi2_d1 */
-                       0x3ac (PIN_INPUT | MUX_MODE0) /* spi2_d0 */
-                       0x3b0 (PIN_INPUT_SLEW | MUX_MODE0) /* spi2_cs0 */
-                       0x3b4 (PIN_INPUT_SLEW | MUX_MODE0) /* spi2_cs1 */
-                       0x3b8 (PIN_INPUT_SLEW | MUX_MODE6) /* spi2_cs2 */
-                       0x3bc (PIN_INPUT_SLEW | MUX_MODE6) /* spi2_cs3 */
+                       0x3a4 (PIN_INPUT | MUX_MODE0) /* spi1_sclk */
+                       0x3a8 (PIN_INPUT | MUX_MODE0) /* spi1_d1 */
+                       0x3ac (PIN_INPUT | MUX_MODE0) /* spi1_d0 */
+                       0x3b0 (PIN_INPUT_SLEW | MUX_MODE0) /* spi1_cs0 */
+                       0x3b8 (PIN_INPUT_SLEW | MUX_MODE6) /* spi1_cs2.hdmi1_hpd */
+                       0x3bc (PIN_INPUT_SLEW | MUX_MODE6) /* spi1_cs3.hdmi1_cec */
                >;
        };
 
        status = "okay";
        pinctrl-names = "default";
        pinctrl-0 = <&i2c3_pins>;
-       clock-frequency = <3400000>;
+       clock-frequency = <400000>;
 };
 
 &mcspi1 {
                        reg = <0x001c0000 0x00020000>;
                };
                partition@7 {
-                       label = "NAND.u-boot-env";
+                       label = "NAND.u-boot-env.backup1";
                        reg = <0x001e0000 0x00020000>;
                };
                partition@8 {
 &usb2_phy2 {
        phy-supply = <&ldousb_reg>;
 };
+
+&gpio7 {
+       ti,no-reset-on-init;
+       ti,no-idle-on-init;
+};
index 97f603c4483d6a46032f06f7961d801091d1b3a4..d678152db4cb39036f7e05a6494737006714e81b 100644 (file)
                        gpio-controller;
                        #gpio-cells = <2>;
                        interrupt-controller;
-                       #interrupt-cells = <1>;
+                       #interrupt-cells = <2>;
                };
 
                gpio2: gpio@48055000 {
                        gpio-controller;
                        #gpio-cells = <2>;
                        interrupt-controller;
-                       #interrupt-cells = <1>;
+                       #interrupt-cells = <2>;
                };
 
                gpio3: gpio@48057000 {
                        gpio-controller;
                        #gpio-cells = <2>;
                        interrupt-controller;
-                       #interrupt-cells = <1>;
+                       #interrupt-cells = <2>;
                };
 
                gpio4: gpio@48059000 {
                        gpio-controller;
                        #gpio-cells = <2>;
                        interrupt-controller;
-                       #interrupt-cells = <1>;
+                       #interrupt-cells = <2>;
                };
 
                gpio5: gpio@4805b000 {
                        gpio-controller;
                        #gpio-cells = <2>;
                        interrupt-controller;
-                       #interrupt-cells = <1>;
+                       #interrupt-cells = <2>;
                };
 
                gpio6: gpio@4805d000 {
                        gpio-controller;
                        #gpio-cells = <2>;
                        interrupt-controller;
-                       #interrupt-cells = <1>;
+                       #interrupt-cells = <2>;
                };
 
                gpio7: gpio@48051000 {
                        gpio-controller;
                        #gpio-cells = <2>;
                        interrupt-controller;
-                       #interrupt-cells = <1>;
+                       #interrupt-cells = <2>;
                };
 
                gpio8: gpio@48053000 {
                        gpio-controller;
                        #gpio-cells = <2>;
                        interrupt-controller;
-                       #interrupt-cells = <1>;
+                       #interrupt-cells = <2>;
                };
 
                uart1: serial@4806a000 {
index 6d6d23c83d30a70e63eae3f5d04d9b8a77da8013..adadaf97ac01b78cf02c05d2e117ae181f1a09a0 100644 (file)
        i2c@13860000 {
                pinctrl-0 = <&i2c0_bus>;
                pinctrl-names = "default";
+               samsung,i2c-sda-delay = <100>;
+               samsung,i2c-max-bus-freq = <400000>;
                status = "okay";
 
                usb3503: usb3503@08 {
 
                max77686: pmic@09 {
                        compatible = "maxim,max77686";
+                       interrupt-parent = <&gpx3>;
+                       interrupts = <2 0>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&max77686_irq>;
                        reg = <0x09>;
                        #clock-cells = <1>;
 
                samsung,pins = "gpx1-3";
                samsung,pin-pud = <0>;
        };
+
+       max77686_irq: max77686-irq {
+               samsung,pins = "gpx3-2";
+               samsung,pin-function = <0>;
+               samsung,pin-pud = <0>;
+               samsung,pin-drv = <0>;
+       };
 };
index f1bbf9a32991dd0b35dc9ee5c72cc9eef0d9246c..82d623d05915813761ecaf8c908dbdafac6af42c 100644 (file)
                                MX53_PAD_CSI0_DAT9__I2C1_SCL      0x400001ec
                        >;
                };
+
+               pinctrl_pmic: pmicgrp {
+                       fsl,pins = <
+                               MX53_PAD_CSI0_DAT5__GPIO5_23    0x1e4 /* IRQ */
+                       >;
+               };
        };
 };
 
@@ -38,6 +44,8 @@
 
        pmic: mc34708@8 {
                compatible = "fsl,mc34708";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_pmic>;
                reg = <0x08>;
                interrupt-parent = <&gpio5>;
                interrupts = <23 0x8>;
index 64fa27b36be0c957b7e8b39610eac563c730b99b..c6c58c1c00e3d866149bc17f12d4cff71fb2b96b 100644 (file)
                                compatible = "fsl,imx53-vpu";
                                reg = <0x63ff4000 0x1000>;
                                interrupts = <9>;
-                               clocks = <&clks IMX5_CLK_VPU_GATE>,
+                               clocks = <&clks IMX5_CLK_VPU_REFERENCE_GATE>,
                                         <&clks IMX5_CLK_VPU_GATE>;
                                clock-names = "per", "ahb";
                                resets = <&src 1>;
index c8e51dd41b8f2e9f729e852ee68140ae896b3ad6..71598546087f366c19baf0faf55b63ceee1ae3ec 100644 (file)
@@ -58,7 +58,7 @@
 
        sound-spdif {
                compatible = "fsl,imx-audio-spdif";
-               model = "imx-spdif";
+               model = "On-board SPDIF";
                /* IMX6 doesn't implement this yet */
                spdif-controller = <&spdif>;
                spdif-out;
 };
 
 &usbh1 {
+       disable-over-current;
        vbus-supply = <&reg_usbh1_vbus>;
        status = "okay";
 };
 
 &usbotg {
+       disable-over-current;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_hummingboard_usbotg_id>;
        vbus-supply = <&reg_usbotg_vbus>;
index 8c1cb53464a0f6bb7e96cd7a412c0a2e2eea8489..4fa25434779828806c49a0d0477a46cb15cd2544 100644 (file)
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_enet>;
        phy-mode = "rgmii";
-       phy-reset-gpios = <&gpio3 23 0>;
+       phy-reset-gpios = <&gpio1 25 0>;
        phy-supply = <&vgen2_1v2_eth>;
        status = "okay";
 };
                                MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK    0x1b0b0
                                MX6QDL_PAD_ENET_MDIO__ENET_MDIO         0x1b0b0
                                MX6QDL_PAD_ENET_MDC__ENET_MDC           0x1b0b0
+                               MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25      0x1b0b0
                                MX6QDL_PAD_GPIO_16__ENET_REF_CLK        0x4001b0a8
                        >;
                };
index e8e781656b3f5ec422800d731768eefb70a88ed7..6a524ca011e70df048939fbc5ef0659c88a660e9 100644 (file)
@@ -61,7 +61,7 @@
 
        sound-spdif {
                compatible = "fsl,imx-audio-spdif";
-               model = "imx-spdif";
+               model = "Integrated SPDIF";
                /* IMX6 doesn't implement this yet */
                spdif-controller = <&spdif>;
                spdif-out;
                        fsl,pins = <MX6QDL_PAD_GPIO_17__SPDIF_OUT 0x13091>;
                };
 
+               pinctrl_cubox_i_usbh1: cubox-i-usbh1 {
+                       fsl,pins = <MX6QDL_PAD_GPIO_3__USB_H1_OC 0x1b0b0>;
+               };
+
                pinctrl_cubox_i_usbh1_vbus: cubox-i-usbh1-vbus {
                        fsl,pins = <MX6QDL_PAD_GPIO_0__GPIO1_IO00 0x4001b0b0>;
                };
 
-               pinctrl_cubox_i_usbotg_id: cubox-i-usbotg-id {
+               pinctrl_cubox_i_usbotg: cubox-i-usbotg {
                        /*
-                        * The Cubox-i pulls this low, but as it's pointless
+                        * The Cubox-i pulls ID low, but as it's pointless
                         * leaving it as a pull-up, even if it is just 10uA.
                         */
-                       fsl,pins = <MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x13059>;
+                       fsl,pins = <
+                               MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x13059
+                               MX6QDL_PAD_KEY_COL4__USB_OTG_OC 0x1b0b0
+                       >;
                };
 
                pinctrl_cubox_i_usbotg_vbus: cubox-i-usbotg-vbus {
 };
 
 &usbh1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_cubox_i_usbh1>;
        vbus-supply = <&reg_usbh1_vbus>;
        status = "okay";
 };
 
 &usbotg {
        pinctrl-names = "default";
-       pinctrl-0 = <&pinctrl_cubox_i_usbotg_id>;
+       pinctrl-0 = <&pinctrl_cubox_i_usbotg>;
        vbus-supply = <&reg_usbotg_vbus>;
        status = "okay";
 };
index d16066608e21ae3716bc52a58597dc51f6ed9241..db9f45b2c57304603a78db4c20ca50a0f133c247 100644 (file)
@@ -17,7 +17,7 @@
        enet {
                pinctrl_microsom_enet_ar8035: microsom-enet-ar8035 {
                        fsl,pins = <
-                               MX6QDL_PAD_ENET_MDIO__ENET_MDIO         0x1b0b0
+                               MX6QDL_PAD_ENET_MDIO__ENET_MDIO         0x1b8b0
                                MX6QDL_PAD_ENET_MDC__ENET_MDC           0x1b0b0
                                /* AR8035 reset */
                                MX6QDL_PAD_KEY_ROW4__GPIO4_IO15         0x130b0
index 3e0b816dac08ff368ef6259d2d67e72df7011bf9..bb9c6b78cb97c676ec03925c5d8ea78bd47579f5 100644 (file)
@@ -78,7 +78,7 @@
 #define MX6SX_PAD_GPIO1_IO07__USDHC2_WP                           0x0030 0x0378 0x0870 0x1 0x1
 #define MX6SX_PAD_GPIO1_IO07__ENET2_MDIO                          0x0030 0x0378 0x0770 0x2 0x0
 #define MX6SX_PAD_GPIO1_IO07__AUDMUX_MCLK                         0x0030 0x0378 0x0000 0x3 0x0
-#define MX6SX_PAD_GPIO1_IO07__UART1_CTS_B                         0x0030 0x0378 0x082C 0x4 0x1
+#define MX6SX_PAD_GPIO1_IO07__UART1_CTS_B                         0x0030 0x0378 0x0000 0x4 0x0
 #define MX6SX_PAD_GPIO1_IO07__GPIO1_IO_7                          0x0030 0x0378 0x0000 0x5 0x0
 #define MX6SX_PAD_GPIO1_IO07__SRC_EARLY_RESET                     0x0030 0x0378 0x0000 0x6 0x0
 #define MX6SX_PAD_GPIO1_IO07__DCIC2_OUT                           0x0030 0x0378 0x0000 0x7 0x0
@@ -96,7 +96,7 @@
 #define MX6SX_PAD_GPIO1_IO09__WDOG2_WDOG_B                        0x0038 0x0380 0x0000 0x1 0x0
 #define MX6SX_PAD_GPIO1_IO09__SDMA_EXT_EVENT_1                    0x0038 0x0380 0x0820 0x2 0x0
 #define MX6SX_PAD_GPIO1_IO09__CCM_OUT0                            0x0038 0x0380 0x0000 0x3 0x0
-#define MX6SX_PAD_GPIO1_IO09__UART2_CTS_B                         0x0038 0x0380 0x0834 0x4 0x1
+#define MX6SX_PAD_GPIO1_IO09__UART2_CTS_B                         0x0038 0x0380 0x0000 0x4 0x0
 #define MX6SX_PAD_GPIO1_IO09__GPIO1_IO_9                          0x0038 0x0380 0x0000 0x5 0x0
 #define MX6SX_PAD_GPIO1_IO09__SRC_INT_BOOT                        0x0038 0x0380 0x0000 0x6 0x0
 #define MX6SX_PAD_GPIO1_IO09__OBSERVE_MUX_OUT_4                   0x0038 0x0380 0x0000 0x7 0x0
 #define MX6SX_PAD_CSI_DATA07__ESAI_TX3_RX2                        0x0068 0x03B0 0x079C 0x1 0x1
 #define MX6SX_PAD_CSI_DATA07__I2C4_SDA                            0x0068 0x03B0 0x07C4 0x2 0x2
 #define MX6SX_PAD_CSI_DATA07__KPP_ROW_7                           0x0068 0x03B0 0x07DC 0x3 0x0
-#define MX6SX_PAD_CSI_DATA07__UART6_CTS_B                         0x0068 0x03B0 0x0854 0x4 0x1
+#define MX6SX_PAD_CSI_DATA07__UART6_CTS_B                         0x0068 0x03B0 0x0000 0x4 0x0
 #define MX6SX_PAD_CSI_DATA07__GPIO1_IO_21                         0x0068 0x03B0 0x0000 0x5 0x0
 #define MX6SX_PAD_CSI_DATA07__WEIM_DATA_16                        0x0068 0x03B0 0x0000 0x6 0x0
 #define MX6SX_PAD_CSI_DATA07__DCIC1_OUT                           0x0068 0x03B0 0x0000 0x7 0x0
 #define MX6SX_PAD_CSI_VSYNC__CSI1_VSYNC                           0x0078 0x03C0 0x0708 0x0 0x0
 #define MX6SX_PAD_CSI_VSYNC__ESAI_TX5_RX0                         0x0078 0x03C0 0x07A4 0x1 0x1
 #define MX6SX_PAD_CSI_VSYNC__AUDMUX_AUD6_RXD                      0x0078 0x03C0 0x0674 0x2 0x1
-#define MX6SX_PAD_CSI_VSYNC__UART4_CTS_B                          0x0078 0x03C0 0x0844 0x3 0x3
+#define MX6SX_PAD_CSI_VSYNC__UART4_CTS_B                          0x0078 0x03C0 0x0000 0x3 0x0
 #define MX6SX_PAD_CSI_VSYNC__MQS_RIGHT                            0x0078 0x03C0 0x0000 0x4 0x0
 #define MX6SX_PAD_CSI_VSYNC__GPIO1_IO_25                          0x0078 0x03C0 0x0000 0x5 0x0
 #define MX6SX_PAD_CSI_VSYNC__WEIM_DATA_24                         0x0078 0x03C0 0x0000 0x6 0x0
 #define MX6SX_PAD_ENET2_TX_CLK__ENET2_TX_CLK                      0x00A0 0x03E8 0x0000 0x0 0x0
 #define MX6SX_PAD_ENET2_TX_CLK__ENET2_REF_CLK2                    0x00A0 0x03E8 0x076C 0x1 0x1
 #define MX6SX_PAD_ENET2_TX_CLK__I2C3_SDA                          0x00A0 0x03E8 0x07BC 0x2 0x1
-#define MX6SX_PAD_ENET2_TX_CLK__UART1_CTS_B                       0x00A0 0x03E8 0x082C 0x3 0x3
+#define MX6SX_PAD_ENET2_TX_CLK__UART1_CTS_B                       0x00A0 0x03E8 0x0000 0x3 0x0
 #define MX6SX_PAD_ENET2_TX_CLK__MLB_CLK                           0x00A0 0x03E8 0x07E8 0x4 0x1
 #define MX6SX_PAD_ENET2_TX_CLK__GPIO2_IO_9                        0x00A0 0x03E8 0x0000 0x5 0x0
 #define MX6SX_PAD_ENET2_TX_CLK__USB_OTG2_PWR                      0x00A0 0x03E8 0x0000 0x6 0x0
 #define MX6SX_PAD_KEY_COL4__SAI2_RX_BCLK                          0x00B4 0x03FC 0x0808 0x7 0x0
 #define MX6SX_PAD_KEY_ROW0__KPP_ROW_0                             0x00B8 0x0400 0x0000 0x0 0x0
 #define MX6SX_PAD_KEY_ROW0__USDHC3_WP                             0x00B8 0x0400 0x0000 0x1 0x0
-#define MX6SX_PAD_KEY_ROW0__UART6_CTS_B                           0x00B8 0x0400 0x0854 0x2 0x3
+#define MX6SX_PAD_KEY_ROW0__UART6_CTS_B                           0x00B8 0x0400 0x0000 0x2 0x0
 #define MX6SX_PAD_KEY_ROW0__ECSPI1_MOSI                           0x00B8 0x0400 0x0718 0x3 0x0
 #define MX6SX_PAD_KEY_ROW0__AUDMUX_AUD5_TXD                       0x00B8 0x0400 0x0660 0x4 0x0
 #define MX6SX_PAD_KEY_ROW0__GPIO2_IO_15                           0x00B8 0x0400 0x0000 0x5 0x0
 #define MX6SX_PAD_KEY_ROW1__M4_NMI                                0x00BC 0x0404 0x0000 0x8 0x0
 #define MX6SX_PAD_KEY_ROW2__KPP_ROW_2                             0x00C0 0x0408 0x0000 0x0 0x0
 #define MX6SX_PAD_KEY_ROW2__USDHC4_WP                             0x00C0 0x0408 0x0878 0x1 0x1
-#define MX6SX_PAD_KEY_ROW2__UART5_CTS_B                           0x00C0 0x0408 0x084C 0x2 0x3
+#define MX6SX_PAD_KEY_ROW2__UART5_CTS_B                           0x00C0 0x0408 0x0000 0x2 0x0
 #define MX6SX_PAD_KEY_ROW2__CAN1_RX                               0x00C0 0x0408 0x068C 0x3 0x1
 #define MX6SX_PAD_KEY_ROW2__CANFD_RX1                             0x00C0 0x0408 0x0694 0x4 0x1
 #define MX6SX_PAD_KEY_ROW2__GPIO2_IO_17                           0x00C0 0x0408 0x0000 0x5 0x0
 #define MX6SX_PAD_NAND_DATA05__RAWNAND_DATA05                     0x0164 0x04AC 0x0000 0x0 0x0
 #define MX6SX_PAD_NAND_DATA05__USDHC2_DATA5                       0x0164 0x04AC 0x0000 0x1 0x0
 #define MX6SX_PAD_NAND_DATA05__QSPI2_B_DQS                        0x0164 0x04AC 0x0000 0x2 0x0
-#define MX6SX_PAD_NAND_DATA05__UART3_CTS_B                        0x0164 0x04AC 0x083C 0x3 0x1
+#define MX6SX_PAD_NAND_DATA05__UART3_CTS_B                        0x0164 0x04AC 0x0000 0x3 0x0
 #define MX6SX_PAD_NAND_DATA05__AUDMUX_AUD4_RXC                    0x0164 0x04AC 0x064C 0x4 0x0
 #define MX6SX_PAD_NAND_DATA05__GPIO4_IO_9                         0x0164 0x04AC 0x0000 0x5 0x0
 #define MX6SX_PAD_NAND_DATA05__WEIM_AD_5                          0x0164 0x04AC 0x0000 0x6 0x0
 #define MX6SX_PAD_QSPI1A_SS1_B__SIM_M_HADDR_12                    0x019C 0x04E4 0x0000 0x7 0x0
 #define MX6SX_PAD_QSPI1A_SS1_B__SDMA_DEBUG_PC_3                   0x019C 0x04E4 0x0000 0x9 0x0
 #define MX6SX_PAD_QSPI1B_DATA0__QSPI1_B_DATA_0                    0x01A0 0x04E8 0x0000 0x0 0x0
-#define MX6SX_PAD_QSPI1B_DATA0__UART3_CTS_B                       0x01A0 0x04E8 0x083C 0x1 0x4
+#define MX6SX_PAD_QSPI1B_DATA0__UART3_CTS_B                       0x01A0 0x04E8 0x0000 0x1 0x0
 #define MX6SX_PAD_QSPI1B_DATA0__ECSPI3_MOSI                       0x01A0 0x04E8 0x0738 0x2 0x1
 #define MX6SX_PAD_QSPI1B_DATA0__ESAI_RX_FS                        0x01A0 0x04E8 0x0778 0x3 0x2
 #define MX6SX_PAD_QSPI1B_DATA0__CSI1_DATA_22                      0x01A0 0x04E8 0x06F4 0x4 0x1
 #define MX6SX_PAD_SD1_DATA2__AUDMUX_AUD5_TXFS                     0x0230 0x0578 0x0670 0x1 0x1
 #define MX6SX_PAD_SD1_DATA2__PWM3_OUT                             0x0230 0x0578 0x0000 0x2 0x0
 #define MX6SX_PAD_SD1_DATA2__GPT_COMPARE2                         0x0230 0x0578 0x0000 0x3 0x0
-#define MX6SX_PAD_SD1_DATA2__UART2_CTS_B                          0x0230 0x0578 0x0834 0x4 0x2
+#define MX6SX_PAD_SD1_DATA2__UART2_CTS_B                          0x0230 0x0578 0x0000 0x4 0x0
 #define MX6SX_PAD_SD1_DATA2__GPIO6_IO_4                           0x0230 0x0578 0x0000 0x5 0x0
 #define MX6SX_PAD_SD1_DATA2__ECSPI4_RDY                           0x0230 0x0578 0x0000 0x6 0x0
 #define MX6SX_PAD_SD1_DATA2__CCM_OUT0                             0x0230 0x0578 0x0000 0x7 0x0
 #define MX6SX_PAD_SD2_DATA3__VADC_CLAMP_CURRENT_3                 0x024C 0x0594 0x0000 0x8 0x0
 #define MX6SX_PAD_SD2_DATA3__MMDC_DEBUG_31                        0x024C 0x0594 0x0000 0x9 0x0
 #define MX6SX_PAD_SD3_CLK__USDHC3_CLK                             0x0250 0x0598 0x0000 0x0 0x0
-#define MX6SX_PAD_SD3_CLK__UART4_CTS_B                            0x0250 0x0598 0x0844 0x1 0x0
+#define MX6SX_PAD_SD3_CLK__UART4_CTS_B                            0x0250 0x0598 0x0000 0x1 0x0
 #define MX6SX_PAD_SD3_CLK__ECSPI4_SCLK                            0x0250 0x0598 0x0740 0x2 0x0
 #define MX6SX_PAD_SD3_CLK__AUDMUX_AUD6_RXFS                       0x0250 0x0598 0x0680 0x3 0x0
 #define MX6SX_PAD_SD3_CLK__LCDIF2_VSYNC                           0x0250 0x0598 0x0000 0x4 0x0
 #define MX6SX_PAD_SD3_DATA7__USDHC3_DATA7                         0x0274 0x05BC 0x0000 0x0 0x0
 #define MX6SX_PAD_SD3_DATA7__CAN1_RX                              0x0274 0x05BC 0x068C 0x1 0x0
 #define MX6SX_PAD_SD3_DATA7__CANFD_RX1                            0x0274 0x05BC 0x0694 0x2 0x0
-#define MX6SX_PAD_SD3_DATA7__UART3_CTS_B                          0x0274 0x05BC 0x083C 0x3 0x3
+#define MX6SX_PAD_SD3_DATA7__UART3_CTS_B                          0x0274 0x05BC 0x0000 0x3 0x0
 #define MX6SX_PAD_SD3_DATA7__LCDIF2_DATA_5                        0x0274 0x05BC 0x0000 0x4 0x0
 #define MX6SX_PAD_SD3_DATA7__GPIO7_IO_9                           0x0274 0x05BC 0x0000 0x5 0x0
 #define MX6SX_PAD_SD3_DATA7__ENET1_1588_EVENT0_IN                 0x0274 0x05BC 0x0000 0x6 0x0
 #define MX6SX_PAD_SD4_DATA6__SDMA_DEBUG_EVENT_CHANNEL_1           0x0298 0x05E0 0x0000 0x9 0x0
 #define MX6SX_PAD_SD4_DATA7__USDHC4_DATA7                         0x029C 0x05E4 0x0000 0x0 0x0
 #define MX6SX_PAD_SD4_DATA7__RAWNAND_DATA08                       0x029C 0x05E4 0x0000 0x1 0x0
-#define MX6SX_PAD_SD4_DATA7__UART5_CTS_B                          0x029C 0x05E4 0x084C 0x2 0x1
+#define MX6SX_PAD_SD4_DATA7__UART5_CTS_B                          0x029C 0x05E4 0x0000 0x2 0x0
 #define MX6SX_PAD_SD4_DATA7__ECSPI3_SS0                           0x029C 0x05E4 0x073C 0x3 0x0
 #define MX6SX_PAD_SD4_DATA7__LCDIF2_DATA_15                       0x029C 0x05E4 0x0000 0x4 0x0
 #define MX6SX_PAD_SD4_DATA7__GPIO6_IO_21                          0x029C 0x05E4 0x0000 0x5 0x0
index 3c3e6da1deacdaddd2ec75cfa2aa3ba8837b929e..a9aae88b74f52687bf896795c83071571dacef73 100644 (file)
 &uart3 {
        pinctrl-names = "default";
        pinctrl-0 = <&uart3_pins>;
+       interrupts-extended = <&intc 74 &omap3_pmx_core OMAP3_UART3_RX>;
 };
 
 &gpio1 {
index b15f1a77d684eac5bad3ea9f0defbf8d549a686a..1fe45d1f75ec8d52aa8dd59a1e344a931fc32576 100644 (file)
        };
 
        twl_power: power {
-               compatible = "ti,twl4030-power-n900";
+               compatible = "ti,twl4030-power-n900", "ti,twl4030-power-idle-osc-off";
                ti,use_poweroff;
        };
 };
index 02f69f4a8fd37739cf12139861760196ed183079..9bad94efe1c81c65a56f9d8fbb6d8fcc53bcd2af 100644 (file)
                #address-cells = <1>;
                #size-cells = <1>;
                reg = <1 0 0x08000000>;
-               ti,nand-ecc-opt = "ham1";
+               ti,nand-ecc-opt = "sw";
                nand-bus-width = <8>;
                gpmc,cs-on-ns = <0>;
                gpmc,cs-rd-off-ns = <36>;
index e47ff69dcf7053e7bb22d3f5d40e7cd09628687c..5c375003bad106216109b5626264300433dabd1d 100644 (file)
                ti,bit-shift = <0x1e>;
                reg = <0x0d00>;
                ti,set-bit-to-disable;
+               ti,set-rate-parent;
        };
 
        dpll4_m6_ck: dpll4_m6_ck {
index e67a23b5d7884725290b6348a54a97f3427ccbc3..58c27466f01262a6f9ecee2058fb11dff9b5df3f 100644 (file)
 
        l3_iclk_div: l3_iclk_div {
                #clock-cells = <0>;
-               compatible = "fixed-factor-clock";
+               compatible = "ti,divider-clock";
+               ti,max-div = <2>;
+               ti,bit-shift = <4>;
+               reg = <0x100>;
                clocks = <&dpll_core_h12x2_ck>;
-               clock-mult = <1>;
-               clock-div = <1>;
+               ti,index-power-of-two;
        };
 
        gpu_l3_iclk: gpu_l3_iclk {
 
        l4_root_clk_div: l4_root_clk_div {
                #clock-cells = <0>;
-               compatible = "fixed-factor-clock";
+               compatible = "ti,divider-clock";
+               ti,max-div = <2>;
+               ti,bit-shift = <8>;
+               reg = <0x100>;
                clocks = <&l3_iclk_div>;
-               clock-mult = <1>;
-               clock-div = <1>;
+               ti,index-power-of-two;
        };
 
        slimbus1_slimbus_clk: slimbus1_slimbus_clk {
index 23486c081a69891096cd08c157d8dfc7fd94384b..be59014474b20114b77ff0d7043b05635b4d9013 100644 (file)
                renesas,function = "msiof0";
        };
 
-       i2c6_pins: i2c6 {
-               renesas,groups = "i2c6";
-               renesas,function = "i2c6";
-       };
-
        usb0_pins: usb0 {
                renesas,groups = "usb0";
                renesas,function = "usb0";
 };
 
 &i2c6 {
-       pinctrl-names = "default";
-       pinctrl-0 = <&i2c6_pins>;
        status = "okay";
        clock-frequency = <100000>;
 
index 042f821d9e4d8bdbe0ab48722293278a86a44496..c9d912da61415b104d62f045b88de810924ac009 100644 (file)
 &mmc0 { /* sdmmc */
        num-slots = <1>;
        status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&sd0_clk>, <&sd0_cmd>, <&sd0_cd>, <&sd0_bus4>;
        vmmc-supply = <&vcc_sd0>;
 
        slot@0 {
index 171b610db709f9e4f94355c31d54d858d89a84c2..d63d685ea6cc9614ede71e7fbcd5755931036311 100644 (file)
        };
 };
 
+&emac {
+       status = "okay";
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&emac_xfer>, <&emac_mdio>, <&phy_int>;
+
+       phy = <&phy0>;
+       phy-supply = <&vcc_rmii>;
+
+       phy0: ethernet-phy@0 {
+               reg = <0>;
+               interrupt-parent = <&gpio3>;
+               interrupts = <26 IRQ_TYPE_LEVEL_LOW>;
+       };
+};
+
 &i2c1 {
        status = "okay";
        clock-frequency = <400000>;
 &mmc0 {
        num-slots = <1>;
        status = "okay";
+       pinctrl-names = "default";
+       pinctrl-0 = <&sd0_clk>, <&sd0_cmd>, <&sd0_cd>, <&sd0_bus4>;
        vmmc-supply = <&vcc_sd0>;
 
        slot@0 {
                };
        };
 
+       lan8720a  {
+               phy_int: phy-int {
+                       rockchip,pins = <RK_GPIO3 26 RK_FUNC_GPIO &pcfg_pull_up>;
+               };
+       };
+
        ir-receiver {
                ir_recv_pin: ir-recv-pin {
                        rockchip,pins = <RK_GPIO0 10 RK_FUNC_GPIO &pcfg_pull_none>;
index ee801a9c6b74144e4a8153908a5e1ad07365bfef..7f25bc51f2ee17ae365fa065024bd48764a5ecbd 100644 (file)
                        bias-disable;
                };
 
+               emac {
+                       emac_xfer: emac-xfer {
+                               rockchip,pins = <RK_GPIO3 16 RK_FUNC_2 &pcfg_pull_none>, /* tx_en */
+                                               <RK_GPIO3 17 RK_FUNC_2 &pcfg_pull_none>, /* txd1 */
+                                               <RK_GPIO3 18 RK_FUNC_2 &pcfg_pull_none>, /* txd0 */
+                                               <RK_GPIO3 19 RK_FUNC_2 &pcfg_pull_none>, /* rxd0 */
+                                               <RK_GPIO3 20 RK_FUNC_2 &pcfg_pull_none>, /* rxd1 */
+                                               <RK_GPIO3 21 RK_FUNC_2 &pcfg_pull_none>, /* mac_clk */
+                                               <RK_GPIO3 22 RK_FUNC_2 &pcfg_pull_none>, /* rx_err */
+                                               <RK_GPIO3 23 RK_FUNC_2 &pcfg_pull_none>; /* crs_dvalid */
+                       };
+
+                       emac_mdio: emac-mdio {
+                               rockchip,pins = <RK_GPIO3 24 RK_FUNC_2 &pcfg_pull_none>,
+                                               <RK_GPIO3 25 RK_FUNC_2 &pcfg_pull_none>;
+                       };
+               };
+
                i2c0 {
                        i2c0_xfer: i2c0-xfer {
                                rockchip,pins = <RK_GPIO1 24 RK_FUNC_1 &pcfg_pull_none>,
        };
 };
 
+&emac {
+       compatible = "rockchip,rk3188-emac";
+};
+
 &global_timer {
        interrupts = <GIC_PPI 11 0xf04>;
 };
index 8caf85d839019ab1ed47690cf9bb4597de71b2f2..208b1df6bcb0789b4d8418677466848e4a58de4b 100644 (file)
                status = "disabled";
        };
 
+       emac: ethernet@10204000 {
+               compatible = "snps,arc-emac";
+               reg = <0x10204000 0x3c>;
+               interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               rockchip,grf = <&grf>;
+
+               clocks = <&cru HCLK_EMAC>, <&cru SCLK_MAC>;
+               clock-names = "hclk", "macref";
+               max-speed = <100>;
+               phy-mode = "rmii";
+
+               status = "disabled";
+       };
+
        mmc0: dwmmc@10214000 {
                compatible = "rockchip,rk2928-dw-mshc";
                reg = <0x10214000 0x1000>;
index 4a2000c620ad7a6a77f3b7aec18efc9a79e3a94e..3e97a669f15ef484107cdef76dbac8051d97202d 100644 (file)
                msp2: msp@80117000 {
                        pinctrl-names = "default";
                        pinctrl-0 = <&msp2_default_mode>;
-                       status = "okay";
                };
 
                msp3: msp@80125000 {
index 44b07e512c2448cbc24821668dc43ceaf6915638..e06fbfc55bb7ee6dee85d601bd3b12fdcac269b6 100644 (file)
                        clock-frequency = <100000>;
                        resets = <&apb2_rst 0>;
                        status = "disabled";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
                };
 
                i2c1: i2c@01c2b000 {
                        clock-frequency = <100000>;
                        resets = <&apb2_rst 1>;
                        status = "disabled";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
                };
 
                i2c2: i2c@01c2b400 {
                        clock-frequency = <100000>;
                        resets = <&apb2_rst 2>;
                        status = "disabled";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
                };
 
                i2c3: i2c@01c2b800 {
                        clock-frequency = <100000>;
                        resets = <&apb2_rst 3>;
                        status = "disabled";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
                };
 
                gmac: ethernet@01c30000 {
index 8adaa7871dd361cf17ac212a79b7d3333c410010..a5446cba9804d3c6c24f7c2207642820869ccaa8 100644 (file)
                        vcc4-supply = <&sys_3v3_reg>;
                        vcc5-supply = <&sys_3v3_reg>;
                        vcc6-supply = <&vio_reg>;
-                       vcc7-supply = <&sys_5v0_reg>;
+                       vcc7-supply = <&charge_pump_5v0_reg>;
                        vccio-supply = <&sys_3v3_reg>;
 
                        regulators {
                        regulator-max-microvolt = <3300000>;
                        regulator-always-on;
                };
+
+               charge_pump_5v0_reg: regulator@101 {
+                       compatible = "regulator-fixed";
+                       reg = <101>;
+                       regulator-name = "5v0";
+                       regulator-min-microvolt = <5000000>;
+                       regulator-max-microvolt = <5000000>;
+                       regulator-always-on;
+               };
        };
 };
index bf16f8e6562767a3c5a5185758fa5e2b72e01a9d..c4ed1bec4d92afad7ae50eb5f16be4748aa77fc3 100644 (file)
                        vcc4-supply = <&sys_3v3_reg>;
                        vcc5-supply = <&sys_3v3_reg>;
                        vcc6-supply = <&vio_reg>;
-                       vcc7-supply = <&sys_5v0_reg>;
+                       vcc7-supply = <&charge_pump_5v0_reg>;
                        vccio-supply = <&sys_3v3_reg>;
 
                        regulators {
                        regulator-max-microvolt = <3300000>;
                        regulator-always-on;
                };
+
+               charge_pump_5v0_reg: regulator@101 {
+                       compatible = "regulator-fixed";
+                       reg = <101>;
+                       regulator-name = "5v0";
+                       regulator-min-microvolt = <5000000>;
+                       regulator-max-microvolt = <5000000>;
+                       regulator-always-on;
+               };
        };
 };
index 2e3bd3172b2366227a78f8404f191e4d0e6e8be6..55eb35f068fb6f9b760d36fd8be2a6f811359754 100644 (file)
                regulator-always-on;
        };
 
-       clk32kg: regulator-clk32kg {
-               compatible = "ti,twl6030-clk32kg";
-       };
-
        twl_usb_comparator: usb-comparator {
                compatible = "ti,twl6030-usb";
                interrupts = <4>, <10>;
index 11d733406c7ed5f1078228b93a1837b3102eedb7..b8a5e8c68f06eedde75d010df044959bfe543d2a 100644 (file)
                };
 
                pinctrl_esdhc1: esdhc1grp {
-                       fsl,fsl,pins = <
+                       fsl,pins = <
                                VF610_PAD_PTA24__ESDHC1_CLK     0x31ef
                                VF610_PAD_PTA25__ESDHC1_CMD     0x31ef
                                VF610_PAD_PTA26__ESDHC1_DAT0    0x31ef
index 88099175fc56c64be13c5a31e5cf05ed18b60e50..d86771abbf57a3760e65c4718a4fbfc6bad8359b 100644 (file)
@@ -1443,14 +1443,14 @@ void edma_assign_channel_eventq(unsigned channel, enum dma_event_q eventq_no)
 EXPORT_SYMBOL(edma_assign_channel_eventq);
 
 static int edma_setup_from_hw(struct device *dev, struct edma_soc_info *pdata,
-                             struct edma *edma_cc)
+                             struct edma *edma_cc, int cc_id)
 {
        int i;
        u32 value, cccfg;
        s8 (*queue_priority_map)[2];
 
        /* Decode the eDMA3 configuration from CCCFG register */
-       cccfg = edma_read(0, EDMA_CCCFG);
+       cccfg = edma_read(cc_id, EDMA_CCCFG);
 
        value = GET_NUM_REGN(cccfg);
        edma_cc->num_region = BIT(value);
@@ -1464,7 +1464,8 @@ static int edma_setup_from_hw(struct device *dev, struct edma_soc_info *pdata,
        value = GET_NUM_EVQUE(cccfg);
        edma_cc->num_tc = value + 1;
 
-       dev_dbg(dev, "eDMA3 HW configuration (cccfg: 0x%08x):\n", cccfg);
+       dev_dbg(dev, "eDMA3 CC%d HW configuration (cccfg: 0x%08x):\n", cc_id,
+               cccfg);
        dev_dbg(dev, "num_region: %u\n", edma_cc->num_region);
        dev_dbg(dev, "num_channel: %u\n", edma_cc->num_channels);
        dev_dbg(dev, "num_slot: %u\n", edma_cc->num_slots);
@@ -1684,7 +1685,7 @@ static int edma_probe(struct platform_device *pdev)
                        return -ENOMEM;
 
                /* Get eDMA3 configuration from IP */
-               ret = edma_setup_from_hw(dev, info[j], edma_cc[j]);
+               ret = edma_setup_from_hw(dev, info[j], edma_cc[j], j);
                if (ret)
                        return ret;
 
index fd43f7f55b701f95393af71be7ef2259139f2586..79ecb4f34ffb34f25037f829a6227ea69b7a9fc8 100644 (file)
@@ -472,7 +472,6 @@ static inline void __sync_cache_range_r(volatile void *p, size_t size)
        "mcr    p15, 0, r0, c1, c0, 0   @ set SCTLR \n\t" \
        "isb    \n\t" \
        "bl     v7_flush_dcache_"__stringify(level)" \n\t" \
-       "clrex  \n\t" \
        "mrc    p15, 0, r0, c1, c0, 1   @ get ACTLR \n\t" \
        "bic    r0, r0, #(1 << 6)       @ disable local coherency \n\t" \
        "mcr    p15, 0, r0, c1, c0, 1   @ set ACTLR \n\t" \
index 963a2515906dce2a2c42e7b924edb6106652497c..819777d0e91f92cb91ff8c1933c480cb1bb80b91 100644 (file)
@@ -74,6 +74,7 @@
 #define ARM_CPU_PART_CORTEX_A12                0x4100c0d0
 #define ARM_CPU_PART_CORTEX_A17                0x4100c0e0
 #define ARM_CPU_PART_CORTEX_A15                0x4100c0f0
+#define ARM_CPU_PART_MASK              0xff00fff0
 
 #define ARM_CPU_XSCALE_ARCH_MASK       0xe000
 #define ARM_CPU_XSCALE_ARCH_V1         0x2000
@@ -179,7 +180,7 @@ static inline unsigned int __attribute_const__ read_cpuid_implementor(void)
  */
 static inline unsigned int __attribute_const__ read_cpuid_part(void)
 {
-       return read_cpuid_id() & 0xff00fff0;
+       return read_cpuid_id() & ARM_CPU_PART_MASK;
 }
 
 static inline unsigned int __attribute_const__ __deprecated read_cpuid_part_number(void)
index f4b46d39b9cfb12756050a992262367ce575f90b..afb9cafd378618fef0d39a7bcae64e9950afdb1c 100644 (file)
@@ -50,6 +50,7 @@ typedef struct user_fp elf_fpregset_t;
 #define R_ARM_ABS32            2
 #define R_ARM_CALL             28
 #define R_ARM_JUMP24           29
+#define R_ARM_TARGET1          38
 #define R_ARM_V4BX             40
 #define R_ARM_PREL31           42
 #define R_ARM_MOVW_ABS_NC      43
index a252c0bfacf50e5adb09d339e42ed0bedfd1ac08..0ad7d490ee6f2657b1504359d362ad8d886bee91 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/cpumask.h>
 #include <linux/err.h>
 
+#include <asm/cpu.h>
 #include <asm/cputype.h>
 
 /*
@@ -25,6 +26,20 @@ static inline bool is_smp(void)
 #endif
 }
 
+/**
+ * smp_cpuid_part() - return part id for a given cpu
+ * @cpu:       logical cpu id.
+ *
+ * Return: part id of logical cpu passed as argument.
+ */
+static inline unsigned int smp_cpuid_part(int cpu)
+{
+       struct cpuinfo_arm *cpu_info = &per_cpu(cpu_data, cpu);
+
+       return is_smp() ? cpu_info->cpuid & ARM_CPU_PART_MASK :
+                         read_cpuid_part();
+}
+
 /* all SMP configurations have the extended CPUID registers */
 #ifndef CONFIG_MMU
 #define tlb_ops_need_broadcast()       0
index 8db307d0954bb03ee95550471dcc0e6f86ae560f..2fdf8679b46e19d1d9e9b0b9c3d196b7c0edbccb 100644 (file)
 #endif
        .endif
        msr     spsr_cxsf, \rpsr
-#if defined(CONFIG_CPU_V6)
-       ldr     r0, [sp]
-       strex   r1, r2, [sp]                    @ clear the exclusive monitor
-       ldmib   sp, {r1 - pc}^                  @ load r1 - pc, cpsr
-#elif defined(CONFIG_CPU_32v6K)
-       clrex                                   @ clear the exclusive monitor
-       ldmia   sp, {r0 - pc}^                  @ load r0 - pc, cpsr
-#else
-       ldmia   sp, {r0 - pc}^                  @ load r0 - pc, cpsr
+#if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_32v6K)
+       @ We must avoid clrex due to Cortex-A15 erratum #830321
+       sub     r0, sp, #4                      @ uninhabited address
+       strex   r1, r2, [r0]                    @ clear the exclusive monitor
 #endif
+       ldmia   sp, {r0 - pc}^                  @ load r0 - pc, cpsr
        .endm
 
        .macro  restore_user_regs, fast = 0, offset = 0
        ldr     r1, [sp, #\offset + S_PSR]      @ get calling cpsr
        ldr     lr, [sp, #\offset + S_PC]!      @ get pc
        msr     spsr_cxsf, r1                   @ save in spsr_svc
-#if defined(CONFIG_CPU_V6)
+#if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_32v6K)
+       @ We must avoid clrex due to Cortex-A15 erratum #830321
        strex   r1, r2, [sp]                    @ clear the exclusive monitor
-#elif defined(CONFIG_CPU_32v6K)
-       clrex                                   @ clear the exclusive monitor
 #endif
        .if     \fast
        ldmdb   sp, {r1 - lr}^                  @ get calling r1 - lr
        .endif
        ldr     lr, [sp, #S_SP]                 @ top of the stack
        ldrd    r0, r1, [sp, #S_LR]             @ calling lr and pc
-       clrex                                   @ clear the exclusive monitor
+
+       @ We must avoid clrex due to Cortex-A15 erratum #830321
+       strex   r2, r1, [sp, #S_LR]             @ clear the exclusive monitor
+
        stmdb   lr!, {r0, r1, \rpsr}            @ calling lr and rfe context
        ldmia   sp, {r0 - r12}
        mov     sp, lr
        .endm
 #else  /* ifdef CONFIG_CPU_V7M */
        .macro  restore_user_regs, fast = 0, offset = 0
-       clrex                                   @ clear the exclusive monitor
        mov     r2, sp
        load_user_sp_lr r2, r3, \offset + S_SP  @ calling sp, lr
        ldr     r1, [sp, #\offset + S_PSR]      @ get calling cpsr
        ldr     lr, [sp, #\offset + S_PC]       @ get pc
        add     sp, sp, #\offset + S_SP
        msr     spsr_cxsf, r1                   @ save in spsr_svc
+
+       @ We must avoid clrex due to Cortex-A15 erratum #830321
+       strex   r1, r2, [sp]                    @ clear the exclusive monitor
+
        .if     \fast
        ldmdb   sp, {r1 - r12}                  @ get calling r1 - r12
        .else
index 45e478157278e331ac6474ca5dbac859415b0fff..6a4dffefd3579994e3d9f1e0b9b02ab3422b738a 100644 (file)
@@ -91,6 +91,7 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
                        break;
 
                case R_ARM_ABS32:
+               case R_ARM_TARGET1:
                        *(u32 *)loc += sym->st_value;
                        break;
 
index 4c979d466cc1681c4b3efc70623345eee5974b78..a96a8043277c3de69cc460a5b2a3f83a36fc30ed 100644 (file)
@@ -93,6 +93,8 @@ static int kvm_handle_wfx(struct kvm_vcpu *vcpu, struct kvm_run *run)
        else
                kvm_vcpu_block(vcpu);
 
+       kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
+
        return 1;
 }
 
index 991415d978b6020a958ac44a886103ee83aa764c..3988e72d16ff9f20efdad72c51dab74b01f559b2 100644 (file)
@@ -99,6 +99,10 @@ __do_hyp_init:
        mrc     p15, 0, r0, c10, c2, 1
        mcr     p15, 4, r0, c10, c2, 1
 
+       @ Invalidate the stale TLBs from Bootloader
+       mcr     p15, 4, r0, c8, c7, 0   @ TLBIALLH
+       dsb     ish
+
        @ Set the HSCTLR to:
        @  - ARM/THUMB exceptions: Kernel config (Thumb-2 kernel)
        @  - Endianness: Kernel config
index 3a185faee795b589725bffd222e2299eac5cffc3..f4b6e91843e44565257982eb7297101bbdbcd4bb 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/gpio.h>
 #include <linux/of.h>
 #include <linux/of_irq.h>
+#include <linux/clk-provider.h>
 
 #include <asm/setup.h>
 #include <asm/irq.h>
@@ -35,13 +36,21 @@ static void __init at91rm9200_dt_init_irq(void)
        of_irq_init(irq_of_match);
 }
 
+static void __init at91rm9200_dt_timer_init(void)
+{
+#if defined(CONFIG_COMMON_CLK)
+       of_clk_init(NULL);
+#endif
+       at91rm9200_timer_init();
+}
+
 static const char *at91rm9200_dt_board_compat[] __initdata = {
        "atmel,at91rm9200",
        NULL
 };
 
 DT_MACHINE_START(at91rm9200_dt, "Atmel AT91RM9200 (Device Tree)")
-       .init_time      = at91rm9200_timer_init,
+       .init_time      = at91rm9200_dt_timer_init,
        .map_io         = at91_map_io,
        .handle_irq     = at91_aic_handle_irq,
        .init_early     = at91rm9200_dt_initialize,
index 67c492aabf4d5ebd3769ff01e304e9371acafafc..b19a39652545daf3ca46243e29c7e7780fb27a91 100644 (file)
@@ -36,5 +36,4 @@ obj-$(CONFIG_ARCH_BCM_5301X)  += bcm_5301x.o
 
 ifeq ($(CONFIG_ARCH_BRCMSTB),y)
 obj-y                          += brcmstb.o
-obj-$(CONFIG_SMP)              += headsmp-brcmstb.o platsmp-brcmstb.o
 endif
diff --git a/arch/arm/mach-bcm/brcmstb.h b/arch/arm/mach-bcm/brcmstb.h
deleted file mode 100644 (file)
index ec0c3d1..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2013-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 version 2.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any
- * kind, whether express or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#ifndef __BRCMSTB_H__
-#define __BRCMSTB_H__
-
-void brcmstb_secondary_startup(void);
-
-#endif /* __BRCMSTB_H__ */
diff --git a/arch/arm/mach-bcm/headsmp-brcmstb.S b/arch/arm/mach-bcm/headsmp-brcmstb.S
deleted file mode 100644 (file)
index 199c1ea..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * SMP boot code for secondary CPUs
- * Based on arch/arm/mach-tegra/headsmp.S
- *
- * Copyright (C) 2010 NVIDIA, Inc.
- * Copyright (C) 2013-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 version 2.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any
- * kind, whether express or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <asm/assembler.h>
-#include <linux/linkage.h>
-#include <linux/init.h>
-
-        .section ".text.head", "ax"
-
-ENTRY(brcmstb_secondary_startup)
-        /*
-         * Ensure CPU is in a sane state by disabling all IRQs and switching
-         * into SVC mode.
-         */
-        setmode        PSR_I_BIT | PSR_F_BIT | SVC_MODE, r0
-
-        bl      v7_invalidate_l1
-        b       secondary_startup
-ENDPROC(brcmstb_secondary_startup)
diff --git a/arch/arm/mach-bcm/platsmp-brcmstb.c b/arch/arm/mach-bcm/platsmp-brcmstb.c
deleted file mode 100644 (file)
index af780e9..0000000
+++ /dev/null
@@ -1,363 +0,0 @@
-/*
- * Broadcom STB CPU SMP and hotplug support for ARM
- *
- * Copyright (C) 2013-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 version 2.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any
- * kind, whether express or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/of_address.h>
-#include <linux/of_platform.h>
-#include <linux/printk.h>
-#include <linux/regmap.h>
-#include <linux/smp.h>
-#include <linux/mfd/syscon.h>
-#include <linux/spinlock.h>
-
-#include <asm/cacheflush.h>
-#include <asm/cp15.h>
-#include <asm/mach-types.h>
-#include <asm/smp_plat.h>
-
-#include "brcmstb.h"
-
-enum {
-       ZONE_MAN_CLKEN_MASK             = BIT(0),
-       ZONE_MAN_RESET_CNTL_MASK        = BIT(1),
-       ZONE_MAN_MEM_PWR_MASK           = BIT(4),
-       ZONE_RESERVED_1_MASK            = BIT(5),
-       ZONE_MAN_ISO_CNTL_MASK          = BIT(6),
-       ZONE_MANUAL_CONTROL_MASK        = BIT(7),
-       ZONE_PWR_DN_REQ_MASK            = BIT(9),
-       ZONE_PWR_UP_REQ_MASK            = BIT(10),
-       ZONE_BLK_RST_ASSERT_MASK        = BIT(12),
-       ZONE_PWR_OFF_STATE_MASK         = BIT(25),
-       ZONE_PWR_ON_STATE_MASK          = BIT(26),
-       ZONE_DPG_PWR_STATE_MASK         = BIT(28),
-       ZONE_MEM_PWR_STATE_MASK         = BIT(29),
-       ZONE_RESET_STATE_MASK           = BIT(31),
-       CPU0_PWR_ZONE_CTRL_REG          = 1,
-       CPU_RESET_CONFIG_REG            = 2,
-};
-
-static void __iomem *cpubiuctrl_block;
-static void __iomem *hif_cont_block;
-static u32 cpu0_pwr_zone_ctrl_reg;
-static u32 cpu_rst_cfg_reg;
-static u32 hif_cont_reg;
-
-#ifdef CONFIG_HOTPLUG_CPU
-static DEFINE_PER_CPU_ALIGNED(int, per_cpu_sw_state);
-
-static int per_cpu_sw_state_rd(u32 cpu)
-{
-       sync_cache_r(SHIFT_PERCPU_PTR(&per_cpu_sw_state, per_cpu_offset(cpu)));
-       return per_cpu(per_cpu_sw_state, cpu);
-}
-
-static void per_cpu_sw_state_wr(u32 cpu, int val)
-{
-       per_cpu(per_cpu_sw_state, cpu) = val;
-       dmb();
-       sync_cache_w(SHIFT_PERCPU_PTR(&per_cpu_sw_state, per_cpu_offset(cpu)));
-       dsb_sev();
-}
-#else
-static inline void per_cpu_sw_state_wr(u32 cpu, int val) { }
-#endif
-
-static void __iomem *pwr_ctrl_get_base(u32 cpu)
-{
-       void __iomem *base = cpubiuctrl_block + cpu0_pwr_zone_ctrl_reg;
-       base += (cpu_logical_map(cpu) * 4);
-       return base;
-}
-
-static u32 pwr_ctrl_rd(u32 cpu)
-{
-       void __iomem *base = pwr_ctrl_get_base(cpu);
-       return readl_relaxed(base);
-}
-
-static void pwr_ctrl_wr(u32 cpu, u32 val)
-{
-       void __iomem *base = pwr_ctrl_get_base(cpu);
-       writel(val, base);
-}
-
-static void cpu_rst_cfg_set(u32 cpu, int set)
-{
-       u32 val;
-       val = readl_relaxed(cpubiuctrl_block + cpu_rst_cfg_reg);
-       if (set)
-               val |= BIT(cpu_logical_map(cpu));
-       else
-               val &= ~BIT(cpu_logical_map(cpu));
-       writel_relaxed(val, cpubiuctrl_block + cpu_rst_cfg_reg);
-}
-
-static void cpu_set_boot_addr(u32 cpu, unsigned long boot_addr)
-{
-       const int reg_ofs = cpu_logical_map(cpu) * 8;
-       writel_relaxed(0, hif_cont_block + hif_cont_reg + reg_ofs);
-       writel_relaxed(boot_addr, hif_cont_block + hif_cont_reg + 4 + reg_ofs);
-}
-
-static void brcmstb_cpu_boot(u32 cpu)
-{
-       pr_info("SMP: Booting CPU%d...\n", cpu);
-
-       /*
-        * set the reset vector to point to the secondary_startup
-        * routine
-        */
-       cpu_set_boot_addr(cpu, virt_to_phys(brcmstb_secondary_startup));
-
-       /* unhalt the cpu */
-       cpu_rst_cfg_set(cpu, 0);
-}
-
-static void brcmstb_cpu_power_on(u32 cpu)
-{
-       /*
-        * The secondary cores power was cut, so we must go through
-        * power-on initialization.
-        */
-       u32 tmp;
-
-       pr_info("SMP: Powering up CPU%d...\n", cpu);
-
-       /* Request zone power up */
-       pwr_ctrl_wr(cpu, ZONE_PWR_UP_REQ_MASK);
-
-       /* Wait for the power up FSM to complete */
-       do {
-               tmp = pwr_ctrl_rd(cpu);
-       } while (!(tmp & ZONE_PWR_ON_STATE_MASK));
-
-       per_cpu_sw_state_wr(cpu, 1);
-}
-
-static int brcmstb_cpu_get_power_state(u32 cpu)
-{
-       int tmp = pwr_ctrl_rd(cpu);
-       return (tmp & ZONE_RESET_STATE_MASK) ? 0 : 1;
-}
-
-#ifdef CONFIG_HOTPLUG_CPU
-
-static void brcmstb_cpu_die(u32 cpu)
-{
-       v7_exit_coherency_flush(all);
-
-       /* Prevent all interrupts from reaching this CPU. */
-       arch_local_irq_disable();
-
-       /*
-        * Final full barrier to ensure everything before this instruction has
-        * quiesced.
-        */
-       isb();
-       dsb();
-
-       per_cpu_sw_state_wr(cpu, 0);
-
-       /* Sit and wait to die */
-       wfi();
-
-       /* We should never get here... */
-       panic("Spurious interrupt on CPU %d received!\n", cpu);
-}
-
-static int brcmstb_cpu_kill(u32 cpu)
-{
-       u32 tmp;
-
-       pr_info("SMP: Powering down CPU%d...\n", cpu);
-
-       while (per_cpu_sw_state_rd(cpu))
-               ;
-
-       /* Program zone reset */
-       pwr_ctrl_wr(cpu, ZONE_RESET_STATE_MASK | ZONE_BLK_RST_ASSERT_MASK |
-                             ZONE_PWR_DN_REQ_MASK);
-
-       /* Verify zone reset */
-       tmp = pwr_ctrl_rd(cpu);
-       if (!(tmp & ZONE_RESET_STATE_MASK))
-               pr_err("%s: Zone reset bit for CPU %d not asserted!\n",
-                       __func__, cpu);
-
-       /* Wait for power down */
-       do {
-               tmp = pwr_ctrl_rd(cpu);
-       } while (!(tmp & ZONE_PWR_OFF_STATE_MASK));
-
-       /* Settle-time from Broadcom-internal DVT reference code */
-       udelay(7);
-
-       /* Assert reset on the CPU */
-       cpu_rst_cfg_set(cpu, 1);
-
-       return 1;
-}
-
-#endif /* CONFIG_HOTPLUG_CPU */
-
-static int __init setup_hifcpubiuctrl_regs(struct device_node *np)
-{
-       int rc = 0;
-       char *name;
-       struct device_node *syscon_np = NULL;
-
-       name = "syscon-cpu";
-
-       syscon_np = of_parse_phandle(np, name, 0);
-       if (!syscon_np) {
-               pr_err("can't find phandle %s\n", name);
-               rc = -EINVAL;
-               goto cleanup;
-       }
-
-       cpubiuctrl_block = of_iomap(syscon_np, 0);
-       if (!cpubiuctrl_block) {
-               pr_err("iomap failed for cpubiuctrl_block\n");
-               rc = -EINVAL;
-               goto cleanup;
-       }
-
-       rc = of_property_read_u32_index(np, name, CPU0_PWR_ZONE_CTRL_REG,
-                                       &cpu0_pwr_zone_ctrl_reg);
-       if (rc) {
-               pr_err("failed to read 1st entry from %s property (%d)\n", name,
-                       rc);
-               rc = -EINVAL;
-               goto cleanup;
-       }
-
-       rc = of_property_read_u32_index(np, name, CPU_RESET_CONFIG_REG,
-                                       &cpu_rst_cfg_reg);
-       if (rc) {
-               pr_err("failed to read 2nd entry from %s property (%d)\n", name,
-                       rc);
-               rc = -EINVAL;
-               goto cleanup;
-       }
-
-cleanup:
-       if (syscon_np)
-               of_node_put(syscon_np);
-
-       return rc;
-}
-
-static int __init setup_hifcont_regs(struct device_node *np)
-{
-       int rc = 0;
-       char *name;
-       struct device_node *syscon_np = NULL;
-
-       name = "syscon-cont";
-
-       syscon_np = of_parse_phandle(np, name, 0);
-       if (!syscon_np) {
-               pr_err("can't find phandle %s\n", name);
-               rc = -EINVAL;
-               goto cleanup;
-       }
-
-       hif_cont_block = of_iomap(syscon_np, 0);
-       if (!hif_cont_block) {
-               pr_err("iomap failed for hif_cont_block\n");
-               rc = -EINVAL;
-               goto cleanup;
-       }
-
-       /* offset is at top of hif_cont_block */
-       hif_cont_reg = 0;
-
-cleanup:
-       if (syscon_np)
-               of_node_put(syscon_np);
-
-       return rc;
-}
-
-static void __init brcmstb_cpu_ctrl_setup(unsigned int max_cpus)
-{
-       int rc;
-       struct device_node *np;
-       char *name;
-
-       name = "brcm,brcmstb-smpboot";
-       np = of_find_compatible_node(NULL, NULL, name);
-       if (!np) {
-               pr_err("can't find compatible node %s\n", name);
-               return;
-       }
-
-       rc = setup_hifcpubiuctrl_regs(np);
-       if (rc)
-               return;
-
-       rc = setup_hifcont_regs(np);
-       if (rc)
-               return;
-}
-
-static DEFINE_SPINLOCK(boot_lock);
-
-static void brcmstb_secondary_init(unsigned int cpu)
-{
-       /*
-        * Synchronise with the boot thread.
-        */
-       spin_lock(&boot_lock);
-       spin_unlock(&boot_lock);
-}
-
-static int brcmstb_boot_secondary(unsigned int cpu, struct task_struct *idle)
-{
-       /*
-        * set synchronisation state between this boot processor
-        * and the secondary one
-        */
-       spin_lock(&boot_lock);
-
-       /* Bring up power to the core if necessary */
-       if (brcmstb_cpu_get_power_state(cpu) == 0)
-               brcmstb_cpu_power_on(cpu);
-
-       brcmstb_cpu_boot(cpu);
-
-       /*
-        * now the secondary core is starting up let it run its
-        * calibrations, then wait for it to finish
-        */
-       spin_unlock(&boot_lock);
-
-       return 0;
-}
-
-static struct smp_operations brcmstb_smp_ops __initdata = {
-       .smp_prepare_cpus       = brcmstb_cpu_ctrl_setup,
-       .smp_secondary_init     = brcmstb_secondary_init,
-       .smp_boot_secondary     = brcmstb_boot_secondary,
-#ifdef CONFIG_HOTPLUG_CPU
-       .cpu_kill               = brcmstb_cpu_kill,
-       .cpu_die                = brcmstb_cpu_die,
-#endif
-};
-
-CPU_METHOD_OF_DECLARE(brcmstb_smp, "brcm,brahma-b15", &brcmstb_smp_ops);
index b2f8b60cf0e9035c0b8eabb4ef6fae098c8bcbf7..dc9a764a7c371d9b1ad5f27e14038cdbeca8690f 100644 (file)
@@ -43,7 +43,6 @@
        "mcr    p15, 0, r0, c1, c0, 0   @ set SCTLR\n\t" \
        "isb\n\t"\
        "bl     v7_flush_dcache_"__stringify(level)"\n\t" \
-       "clrex\n\t"\
        "mrc    p15, 0, r0, c1, c0, 1   @ get ACTLR\n\t" \
        "bic    r0, r0, #(1 << 6)       @ disable local coherency\n\t" \
        /* Dummy Load of a device register to avoid Erratum 799270 */ \
index 9de84a215abd98adc78e9c480d19603da6e82637..be9a51afe05a02ff374f6c4d73db362907fa49ea 100644 (file)
@@ -85,7 +85,6 @@ config SOC_IMX25
 
 config SOC_IMX27
        bool
-       select ARCH_HAS_OPP
        select CPU_ARM926T
        select IMX_HAVE_IOMUX_V1
        select MXC_AVIC
@@ -659,7 +658,6 @@ comment "Device tree only"
 
 config SOC_IMX5
        bool
-       select ARCH_HAS_OPP
        select HAVE_IMX_SRC
        select MXC_TZIC
 
index ac88599ca0805a5cc7da4c79f308fe83963183c4..23c02932bf843e1c4862f7c18b16b49f4a0d4551 100644 (file)
@@ -93,9 +93,11 @@ obj-$(CONFIG_HAVE_IMX_ANATOP) += anatop.o
 obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o
 obj-$(CONFIG_HAVE_IMX_MMDC) += mmdc.o
 obj-$(CONFIG_HAVE_IMX_SRC) += src.o
+ifdef CONFIG_SOC_IMX6
 AFLAGS_headsmp.o :=-Wa,-march=armv7-a
 obj-$(CONFIG_SMP) += headsmp.o platsmp.o
 obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
+endif
 obj-$(CONFIG_SOC_IMX6Q) += clk-imx6q.o mach-imx6q.o
 obj-$(CONFIG_SOC_IMX6SL) += clk-imx6sl.o mach-imx6sl.o
 obj-$(CONFIG_SOC_IMX6SX) += clk-imx6sx.o mach-imx6sx.o
index 6cceb7765c14a19f9426309376e13268e3f2091a..29d412975affce9b4141fb7b3e99716b6b49b2f0 100644 (file)
@@ -194,6 +194,10 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
        clk[IMX6QDL_CLK_PLL3_80M]  = imx_clk_fixed_factor("pll3_80m",  "pll3_usb_otg",   1, 6);
        clk[IMX6QDL_CLK_PLL3_60M]  = imx_clk_fixed_factor("pll3_60m",  "pll3_usb_otg",   1, 8);
        clk[IMX6QDL_CLK_TWD]       = imx_clk_fixed_factor("twd",       "arm",            1, 2);
+       if (cpu_is_imx6dl()) {
+               clk[IMX6QDL_CLK_GPU2D_AXI] = imx_clk_fixed_factor("gpu2d_axi", "mmdc_ch0_axi_podf", 1, 1);
+               clk[IMX6QDL_CLK_GPU3D_AXI] = imx_clk_fixed_factor("gpu3d_axi", "mmdc_ch0_axi_podf", 1, 1);
+       }
 
        clk[IMX6QDL_CLK_PLL4_POST_DIV] = clk_register_divider_table(NULL, "pll4_post_div", "pll4_audio", CLK_SET_RATE_PARENT, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock);
        clk[IMX6QDL_CLK_PLL4_AUDIO_DIV] = clk_register_divider(NULL, "pll4_audio_div", "pll4_post_div", CLK_SET_RATE_PARENT, base + 0x170, 15, 1, 0, &imx_ccm_lock);
@@ -217,8 +221,10 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
        clk[IMX6QDL_CLK_ESAI_SEL]         = imx_clk_mux("esai_sel",         base + 0x20, 19, 2, audio_sels,        ARRAY_SIZE(audio_sels));
        clk[IMX6QDL_CLK_ASRC_SEL]         = imx_clk_mux("asrc_sel",         base + 0x30, 7,  2, audio_sels,        ARRAY_SIZE(audio_sels));
        clk[IMX6QDL_CLK_SPDIF_SEL]        = imx_clk_mux("spdif_sel",        base + 0x30, 20, 2, audio_sels,        ARRAY_SIZE(audio_sels));
-       clk[IMX6QDL_CLK_GPU2D_AXI]        = imx_clk_mux("gpu2d_axi",        base + 0x18, 0,  1, gpu_axi_sels,      ARRAY_SIZE(gpu_axi_sels));
-       clk[IMX6QDL_CLK_GPU3D_AXI]        = imx_clk_mux("gpu3d_axi",        base + 0x18, 1,  1, gpu_axi_sels,      ARRAY_SIZE(gpu_axi_sels));
+       if (cpu_is_imx6q()) {
+               clk[IMX6QDL_CLK_GPU2D_AXI]        = imx_clk_mux("gpu2d_axi",        base + 0x18, 0,  1, gpu_axi_sels,      ARRAY_SIZE(gpu_axi_sels));
+               clk[IMX6QDL_CLK_GPU3D_AXI]        = imx_clk_mux("gpu3d_axi",        base + 0x18, 1,  1, gpu_axi_sels,      ARRAY_SIZE(gpu_axi_sels));
+       }
        clk[IMX6QDL_CLK_GPU2D_CORE_SEL]   = imx_clk_mux("gpu2d_core_sel",   base + 0x18, 16, 2, gpu2d_core_sels,   ARRAY_SIZE(gpu2d_core_sels));
        clk[IMX6QDL_CLK_GPU3D_CORE_SEL]   = imx_clk_mux("gpu3d_core_sel",   base + 0x18, 4,  2, gpu3d_core_sels,   ARRAY_SIZE(gpu3d_core_sels));
        clk[IMX6QDL_CLK_GPU3D_SHADER_SEL] = imx_clk_mux("gpu3d_shader_sel", base + 0x18, 8,  2, gpu3d_shader_sels, ARRAY_SIZE(gpu3d_shader_sels));
index 74b50f1982dbc3526e8cb1a84b25ffff188dd45b..ca4ea2daf25b3e7da3bae73151abff8146154bf3 100644 (file)
@@ -173,6 +173,8 @@ ENTRY(imx6_suspend)
        ldr     r6, [r11, #0x0]
        ldr     r11, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET]
        ldr     r6, [r11, #0x0]
+       ldr     r11, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET]
+       ldr     r6, [r11, #0x0]
 
        /* use r11 to store the IO address */
        ldr     r11, [r0, #PM_INFO_MX6Q_SRC_V_OFFSET]
index e87f2a83d6bfccf809fe6d5c1cf16cbd474a8f70..2d245c2e641cd9314378def624b45093951a59cc 100644 (file)
@@ -142,7 +142,7 @@ __init board_nand_init(struct mtd_partition *nand_parts, u8 nr_parts, u8 cs,
        board_nand_data.nr_parts        = nr_parts;
        board_nand_data.devsize         = nand_type;
 
-       board_nand_data.ecc_opt = OMAP_ECC_HAM1_CODE_HW;
+       board_nand_data.ecc_opt = OMAP_ECC_HAM1_CODE_SW;
        gpmc_nand_init(&board_nand_data, gpmc_t);
 }
 #endif /* CONFIG_MTD_NAND_OMAP2 || CONFIG_MTD_NAND_OMAP2_MODULE */
index 8897ad7035fd448bf8021a9aea06c3684639fb3f..cb7764314f1736206c9dba849e2e777c76cbb1e7 100644 (file)
@@ -49,7 +49,8 @@ static bool gpmc_hwecc_bch_capable(enum omap_ecc ecc_opt)
                return 0;
 
        /* legacy platforms support only HAM1 (1-bit Hamming) ECC scheme */
-       if (ecc_opt == OMAP_ECC_HAM1_CODE_HW)
+       if (ecc_opt == OMAP_ECC_HAM1_CODE_HW ||
+           ecc_opt == OMAP_ECC_HAM1_CODE_SW)
                return 1;
        else
                return 0;
index 8bc13380f0a06ec14859b8c274883142a14ef968..2f97228f188aa3a835146d81bb7bffc2edcb039d 100644 (file)
@@ -1207,8 +1207,7 @@ int gpmc_cs_program_settings(int cs, struct gpmc_settings *p)
                }
        }
 
-       if ((p->wait_on_read || p->wait_on_write) &&
-           (p->wait_pin > gpmc_nr_waitpins)) {
+       if (p->wait_pin > gpmc_nr_waitpins) {
                pr_err("%s: invalid wait-pin (%d)\n", __func__, p->wait_pin);
                return -EINVAL;
        }
@@ -1288,8 +1287,8 @@ void gpmc_read_settings_dt(struct device_node *np, struct gpmc_settings *p)
                p->wait_on_write = of_property_read_bool(np,
                                                         "gpmc,wait-on-write");
                if (!p->wait_on_read && !p->wait_on_write)
-                       pr_warn("%s: read/write wait monitoring not enabled!\n",
-                               __func__);
+                       pr_debug("%s: rd/wr wait monitoring not enabled!\n",
+                                __func__);
        }
 }
 
@@ -1403,8 +1402,11 @@ static int gpmc_probe_nand_child(struct platform_device *pdev,
                pr_err("%s: ti,nand-ecc-opt not found\n", __func__);
                return -ENODEV;
        }
-       if (!strcmp(s, "ham1") || !strcmp(s, "sw") ||
-               !strcmp(s, "hw") || !strcmp(s, "hw-romcode"))
+
+       if (!strcmp(s, "sw"))
+               gpmc_nand_data->ecc_opt = OMAP_ECC_HAM1_CODE_SW;
+       else if (!strcmp(s, "ham1") ||
+                !strcmp(s, "hw") || !strcmp(s, "hw-romcode"))
                gpmc_nand_data->ecc_opt =
                                OMAP_ECC_HAM1_CODE_HW;
        else if (!strcmp(s, "bch4"))
index d42022f2a71e67c6588fda9b02294625940bb3bf..53841dea80ea5c2eaf040c8180922c95ccff18b1 100644 (file)
@@ -663,7 +663,7 @@ void __init dra7xxx_check_revision(void)
 
        default:
                /* Unknown default to latest silicon rev as default*/
-               pr_warn("%s: unknown idcode=0x%08x (hawkeye=0x%08x,rev=0x%d)\n",
+               pr_warn("%s: unknown idcode=0x%08x (hawkeye=0x%08x,rev=0x%x)\n",
                        __func__, idcode, hawkeye, rev);
                omap_revision = DRA752_REV_ES1_1;
        }
index 01ef59def44b86e84a5a1afc1b84d34f0caa17e4..d22c30d3ccfa0809d2662cbd5390c20f40b24a55 100644 (file)
@@ -56,7 +56,7 @@ static void _add_clkdev(struct omap_device *od, const char *clk_alias,
 
        r = clk_get_sys(dev_name(&od->pdev->dev), clk_alias);
        if (!IS_ERR(r)) {
-               dev_warn(&od->pdev->dev,
+               dev_dbg(&od->pdev->dev,
                         "alias %s already exists\n", clk_alias);
                clk_put(r);
                return;
index 6c074f37cdd2ac57aa6a1ba2673b5e9fbcb3c3ca..8fd87a3055bf6c4a084a25a51f19e4263567add7 100644 (file)
@@ -2185,6 +2185,8 @@ static int _enable(struct omap_hwmod *oh)
                         oh->mux->pads_dynamic))) {
                omap_hwmod_mux(oh->mux, _HWMOD_STATE_ENABLED);
                _reconfigure_io_chain();
+       } else if (oh->flags & HWMOD_FORCE_MSTANDBY) {
+               _reconfigure_io_chain();
        }
 
        _add_initiator_dep(oh, mpu_oh);
@@ -2291,6 +2293,8 @@ static int _idle(struct omap_hwmod *oh)
        if (oh->mux && oh->mux->pads_dynamic) {
                omap_hwmod_mux(oh->mux, _HWMOD_STATE_IDLE);
                _reconfigure_io_chain();
+       } else if (oh->flags & HWMOD_FORCE_MSTANDBY) {
+               _reconfigure_io_chain();
        }
 
        oh->_state = _HWMOD_STATE_IDLE;
@@ -3345,6 +3349,9 @@ int __init omap_hwmod_register_links(struct omap_hwmod_ocp_if **ois)
        if (!ois)
                return 0;
 
+       if (ois[0] == NULL) /* Empty list */
+               return 0;
+
        if (!linkspace) {
                if (_alloc_linkspace(ois)) {
                        pr_err("omap_hwmod: could not allocate link space\n");
index 2757abf87fbc5216662daa5ae87e06c991940756..5684f112654bb9dc6688f43fc2defa58dcbf7d65 100644 (file)
@@ -35,6 +35,7 @@
 #include "i2c.h"
 #include "mmc.h"
 #include "wd_timer.h"
+#include "soc.h"
 
 /* Base offset for all DRA7XX interrupts external to MPUSS */
 #define DRA7XX_IRQ_GIC_START   32
@@ -3261,7 +3262,6 @@ static struct omap_hwmod_ocp_if *dra7xx_hwmod_ocp_ifs[] __initdata = {
        &dra7xx_l4_per3__usb_otg_ss1,
        &dra7xx_l4_per3__usb_otg_ss2,
        &dra7xx_l4_per3__usb_otg_ss3,
-       &dra7xx_l4_per3__usb_otg_ss4,
        &dra7xx_l3_main_1__vcp1,
        &dra7xx_l4_per2__vcp1,
        &dra7xx_l3_main_1__vcp2,
@@ -3270,8 +3270,26 @@ static struct omap_hwmod_ocp_if *dra7xx_hwmod_ocp_ifs[] __initdata = {
        NULL,
 };
 
+static struct omap_hwmod_ocp_if *dra74x_hwmod_ocp_ifs[] __initdata = {
+       &dra7xx_l4_per3__usb_otg_ss4,
+       NULL,
+};
+
+static struct omap_hwmod_ocp_if *dra72x_hwmod_ocp_ifs[] __initdata = {
+       NULL,
+};
+
 int __init dra7xx_hwmod_init(void)
 {
+       int ret;
+
        omap_hwmod_init();
-       return omap_hwmod_register_links(dra7xx_hwmod_ocp_ifs);
+       ret = omap_hwmod_register_links(dra7xx_hwmod_ocp_ifs);
+
+       if (!ret && soc_is_dra74x())
+               return omap_hwmod_register_links(dra74x_hwmod_ocp_ifs);
+       else if (!ret && soc_is_dra72x())
+               return omap_hwmod_register_links(dra72x_hwmod_ocp_ifs);
+
+       return ret;
 }
index 01ca8086fb6c734a984b973fb4bfab30eff152e6..4376f59626d1fd5b1117eb4de8d1c33ba6e5ef01 100644 (file)
@@ -245,6 +245,8 @@ IS_AM_SUBCLASS(437x, 0x437)
 #define soc_is_omap54xx()              0
 #define soc_is_omap543x()              0
 #define soc_is_dra7xx()                        0
+#define soc_is_dra74x()                        0
+#define soc_is_dra72x()                        0
 
 #if defined(MULTI_OMAP2)
 # if defined(CONFIG_ARCH_OMAP2)
@@ -393,7 +395,11 @@ IS_OMAP_TYPE(3430, 0x3430)
 
 #if defined(CONFIG_SOC_DRA7XX)
 #undef soc_is_dra7xx
+#undef soc_is_dra74x
+#undef soc_is_dra72x
 #define soc_is_dra7xx()        (of_machine_is_compatible("ti,dra7"))
+#define soc_is_dra74x()        (of_machine_is_compatible("ti,dra74"))
+#define soc_is_dra72x()        (of_machine_is_compatible("ti,dra72"))
 #endif
 
 /* Various silicon revisions for omap2 */
index e15dff790dbbbdc4aaa9937bbff18072828369b9..1e6c51c7c2d5694d0581603f355bb6e4fbc16108 100644 (file)
@@ -75,6 +75,7 @@ config ARCH_SH7372
        select ARM_CPU_SUSPEND if PM || CPU_IDLE
        select CPU_V7
        select SH_CLK_CPG
+       select SH_INTC
        select SYS_SUPPORTS_SH_CMT
        select SYS_SUPPORTS_SH_TMU
 
@@ -85,6 +86,7 @@ config ARCH_SH73A0
        select CPU_V7
        select I2C
        select SH_CLK_CPG
+       select SH_INTC
        select RENESAS_INTC_IRQPIN
        select SYS_SUPPORTS_SH_CMT
        select SYS_SUPPORTS_SH_TMU
index 17435c1aa2fe318ceeb4692632bd986ce5484655..126ddafad5265dc62793fd6e7f25aea16b7c42e1 100644 (file)
@@ -183,8 +183,8 @@ enum {
 
 static struct clk div4_clks[DIV4_NR] = {
        [DIV4_SDH] = SH_CLK_DIV4(&pll1_clk, SDCKCR, 8, 0x0dff, CLK_ENABLE_ON_INIT),
-       [DIV4_SD0] = SH_CLK_DIV4(&pll1_clk, SDCKCR, 4, 0x1de0, CLK_ENABLE_ON_INIT),
-       [DIV4_SD1] = SH_CLK_DIV4(&pll1_clk, SDCKCR, 0, 0x1de0, CLK_ENABLE_ON_INIT),
+       [DIV4_SD0] = SH_CLK_DIV4(&pll1_clk, SDCKCR, 4, 0x1df0, CLK_ENABLE_ON_INIT),
+       [DIV4_SD1] = SH_CLK_DIV4(&pll1_clk, SDCKCR, 0, 0x1df0, CLK_ENABLE_ON_INIT),
 };
 
 /* DIV6 clocks */
index 10e193d707f531216776695b5da2cf0c65de418a..453b23129cfa0cd3903e7ebdc3aaef8009bb3542 100644 (file)
@@ -152,7 +152,7 @@ enum {
 
 static struct clk div4_clks[DIV4_NR] = {
        [DIV4_SDH] = SH_CLK_DIV4(&pll1_clk, SDCKCR, 8, 0x0dff, CLK_ENABLE_ON_INIT),
-       [DIV4_SD0] = SH_CLK_DIV4(&pll1_clk, SDCKCR, 4, 0x1de0, CLK_ENABLE_ON_INIT),
+       [DIV4_SD0] = SH_CLK_DIV4(&pll1_clk, SDCKCR, 4, 0x1df0, CLK_ENABLE_ON_INIT),
 };
 
 /* DIV6 clocks */
index d8c4048b9e338d345bb5e5ceb682e3ded7df09ce..02a6f45a0b9e1c832d5c5d6bfcb79395a42363a2 100644 (file)
@@ -644,7 +644,7 @@ static struct clk_lookup lookups[] = {
        CLKDEV_DEV_ID("sh-sci.5", &mstp_clks[MSTP207]), /* SCIFA5 */
        CLKDEV_DEV_ID("e6cb0000.serial", &mstp_clks[MSTP207]), /* SCIFA5 */
        CLKDEV_DEV_ID("sh-sci.8", &mstp_clks[MSTP206]), /* SCIFB */
-       CLKDEV_DEV_ID("0xe6c3000.serial", &mstp_clks[MSTP206]), /* SCIFB */
+       CLKDEV_DEV_ID("e6c3000.serial", &mstp_clks[MSTP206]), /* SCIFB */
        CLKDEV_DEV_ID("sh-sci.0", &mstp_clks[MSTP204]), /* SCIFA0 */
        CLKDEV_DEV_ID("e6c40000.serial", &mstp_clks[MSTP204]), /* SCIFA0 */
        CLKDEV_DEV_ID("sh-sci.1", &mstp_clks[MSTP203]), /* SCIFA1 */
index 2c2754e79cb37d3fbcd9aff04ca086e4ba6f5274..f61158c6ce7185a3b30ef396116a7fc2d74b3c72 100644 (file)
@@ -426,9 +426,15 @@ static int ve_spc_populate_opps(uint32_t cluster)
 
 static int ve_init_opp_table(struct device *cpu_dev)
 {
-       int cluster = topology_physical_package_id(cpu_dev->id);
-       int idx, ret = 0, max_opp = info->num_opps[cluster];
-       struct ve_spc_opp *opps = info->opps[cluster];
+       int cluster;
+       int idx, ret = 0, max_opp;
+       struct ve_spc_opp *opps;
+
+       cluster = topology_physical_package_id(cpu_dev->id);
+       cluster = cluster < 0 ? 0 : cluster;
+
+       max_opp = info->num_opps[cluster];
+       opps = info->opps[cluster];
 
        for (idx = 0; idx < max_opp; idx++, opps++) {
                ret = dev_pm_opp_add(cpu_dev, opps->freq * 1000, opps->u_volt);
@@ -537,6 +543,8 @@ static struct clk *ve_spc_clk_register(struct device *cpu_dev)
        spc->hw.init = &init;
        spc->cluster = topology_physical_package_id(cpu_dev->id);
 
+       spc->cluster = spc->cluster < 0 ? 0 : spc->cluster;
+
        init.name = dev_name(cpu_dev);
        init.ops = &clk_spc_ops;
        init.flags = CLK_IS_ROOT | CLK_GET_RATE_NOCACHE;
index 3815a8262af070b98f33d61ac31908961ee06eb2..8c48c5c22a331aac8f547335d6990c598457ef0b 100644 (file)
  */
        .align  5
 ENTRY(v6_early_abort)
-#ifdef CONFIG_CPU_V6
-       sub     r1, sp, #4                      @ Get unused stack location
-       strex   r0, r1, [r1]                    @ Clear the exclusive monitor
-#elif defined(CONFIG_CPU_32v6K)
-       clrex
-#endif
        mrc     p15, 0, r1, c5, c0, 0           @ get FSR
        mrc     p15, 0, r0, c6, c0, 0           @ get FAR
 /*
index 703375277ba6d3dcdae7f93404d2d19e531aad68..4812ad054214572ba6e7198247e2c190e469897d 100644 (file)
  */
        .align  5
 ENTRY(v7_early_abort)
-       /*
-        * The effect of data aborts on on the exclusive access monitor are
-        * UNPREDICTABLE. Do a CLREX to clear the state
-        */
-       clrex
-
        mrc     p15, 0, r1, c5, c0, 0           @ get FSR
        mrc     p15, 0, r0, c6, c0, 0           @ get FAR
 
index a37b989a2f91e302be654a7633082321e8f0c5bb..6b45f649eff0c1c205224f2af2e8e4ae1fc79bbe 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/compiler.h>
 #include <linux/errno.h>
 #include <linux/filter.h>
-#include <linux/moduleloader.h>
 #include <linux/netdevice.h>
 #include <linux/string.h>
 #include <linux/slab.h>
@@ -174,6 +173,15 @@ static inline bool is_load_to_a(u16 inst)
        }
 }
 
+static void jit_fill_hole(void *area, unsigned int size)
+{
+       /* Insert illegal UND instructions. */
+       u32 *ptr, fill_ins = 0xe7ffffff;
+       /* We are guaranteed to have aligned memory. */
+       for (ptr = area; size >= sizeof(u32); size -= sizeof(u32))
+               *ptr++ = fill_ins;
+}
+
 static void build_prologue(struct jit_ctx *ctx)
 {
        u16 reg_set = saved_regs(ctx);
@@ -859,9 +867,11 @@ b_epilogue:
 
 void bpf_jit_compile(struct bpf_prog *fp)
 {
+       struct bpf_binary_header *header;
        struct jit_ctx ctx;
        unsigned tmp_idx;
        unsigned alloc_size;
+       u8 *target_ptr;
 
        if (!bpf_jit_enable)
                return;
@@ -897,13 +907,15 @@ void bpf_jit_compile(struct bpf_prog *fp)
        /* there's nothing after the epilogue on ARMv7 */
        build_epilogue(&ctx);
 #endif
-
        alloc_size = 4 * ctx.idx;
-       ctx.target = module_alloc(alloc_size);
-       if (unlikely(ctx.target == NULL))
+       header = bpf_jit_binary_alloc(alloc_size, &target_ptr,
+                                     4, jit_fill_hole);
+       if (header == NULL)
                goto out;
 
+       ctx.target = (u32 *) target_ptr;
        ctx.idx = 0;
+
        build_prologue(&ctx);
        build_body(&ctx);
        build_epilogue(&ctx);
@@ -919,8 +931,9 @@ void bpf_jit_compile(struct bpf_prog *fp)
                /* there are 2 passes here */
                bpf_jit_dump(fp->len, alloc_size, 2, ctx.target);
 
+       set_memory_ro((unsigned long)header, header->pages);
        fp->bpf_func = (void *)ctx.target;
-       fp->jited = 1;
+       fp->jited = true;
 out:
        kfree(ctx.offsets);
        return;
@@ -928,7 +941,15 @@ out:
 
 void bpf_jit_free(struct bpf_prog *fp)
 {
-       if (fp->jited)
-               module_free(NULL, fp->bpf_func);
-       kfree(fp);
+       unsigned long addr = (unsigned long)fp->bpf_func & PAGE_MASK;
+       struct bpf_binary_header *header = (void *)addr;
+
+       if (!fp->jited)
+               goto free_filter;
+
+       set_memory_rw(addr, header->pages);
+       bpf_jit_binary_free(header);
+
+free_filter:
+       bpf_prog_unlock_free(fp);
 }
index 57833546bf003b5f8ffe5e70fb65c10c8dd1ef55..2df5e5daeebeaca04dc9c9948556b75eb21ffe78 100644 (file)
@@ -39,7 +39,7 @@ head-y                := arch/arm64/kernel/head.o
 
 # The byte offset of the kernel image in RAM from the start of RAM.
 ifeq ($(CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET), y)
-TEXT_OFFSET := $(shell awk 'BEGIN {srand(); printf "0x%04x0\n", int(65535 * rand())}')
+TEXT_OFFSET := $(shell awk 'BEGIN {srand(); printf "0x%03x000\n", int(512 * rand())}')
 else
 TEXT_OFFSET := 0x00080000
 endif
index 1e52b741d80644f0f293d247d412781dc18895e9..d92ef3c541617ec5bbe5a45f8da91bd9e27d1461 100644 (file)
@@ -64,6 +64,8 @@ CONFIG_VIRTIO_BLK=y
 CONFIG_BLK_DEV_SD=y
 # CONFIG_SCSI_LOWLEVEL is not set
 CONFIG_ATA=y
+CONFIG_AHCI_XGENE=y
+CONFIG_PHY_XGENE=y
 CONFIG_PATA_PLATFORM=y
 CONFIG_PATA_OF_PLATFORM=y
 CONFIG_NETDEVICES=y
@@ -71,6 +73,7 @@ CONFIG_TUN=y
 CONFIG_VIRTIO_NET=y
 CONFIG_SMC91X=y
 CONFIG_SMSC911X=y
+CONFIG_NET_XGENE=y
 # CONFIG_WLAN is not set
 CONFIG_INPUT_EVDEV=y
 # CONFIG_SERIO_SERPORT is not set
index c294e67d3925e13401526b4b57ce9637bdb92092..ae67e88c28b99497b4ae394bc849bdb20cacdd02 100644 (file)
@@ -150,7 +150,6 @@ static void sha2_finup(struct shash_desc *desc, const u8 *data,
        kernel_neon_begin_partial(28);
        sha2_ce_transform(blocks, data, sctx->state, NULL, len);
        kernel_neon_end();
-       data += blocks * SHA256_BLOCK_SIZE;
 }
 
 static int sha224_finup(struct shash_desc *desc, const u8 *data,
index d064047612b12acb2668927c4b3cedf504d22c11..52b484b6aa1a7fec251a72b028f655523c74236a 100644 (file)
@@ -79,7 +79,6 @@ static inline void decode_ctrl_reg(u32 reg,
  */
 #define ARM_MAX_BRP            16
 #define ARM_MAX_WRP            16
-#define ARM_MAX_HBP_SLOTS      (ARM_MAX_BRP + ARM_MAX_WRP)
 
 /* Virtual debug register bases. */
 #define AARCH64_DBG_REG_BVR    0
index 3df21feeabddfca221e3a65063634ca339e4c0d9..286b1bec547ce2a060d01cf816893b2b4aef9d12 100644 (file)
@@ -139,7 +139,7 @@ extern struct task_struct *cpu_switch_to(struct task_struct *prev,
        ((struct pt_regs *)(THREAD_START_SP + task_stack_page(p)) - 1)
 
 #define KSTK_EIP(tsk)  ((unsigned long)task_pt_regs(tsk)->pc)
-#define KSTK_ESP(tsk)  ((unsigned long)task_pt_regs(tsk)->sp)
+#define KSTK_ESP(tsk)  user_stack_pointer(task_pt_regs(tsk))
 
 /*
  * Prefetching support
index 501000fadb6fde2249096d3dc6ee027cba427e14..41ed9e13795e59411b701f7590d3a5386f52ba01 100644 (file)
@@ -137,7 +137,7 @@ struct pt_regs {
        (!((regs)->pstate & PSR_F_BIT))
 
 #define user_stack_pointer(regs) \
-       (!compat_user_mode(regs)) ? ((regs)->sp) : ((regs)->compat_sp)
+       (!compat_user_mode(regs) ? (regs)->sp : (regs)->compat_sp)
 
 static inline unsigned long regs_return_value(struct pt_regs *regs)
 {
index 1be62bcb9d474e42e6b457eaecc4272bfc37d2b1..74a9d301819fbfa1128bcce879b95ae9c24a2e76 100644 (file)
@@ -17,7 +17,7 @@
 #define __ASM_SPARSEMEM_H
 
 #ifdef CONFIG_SPARSEMEM
-#define MAX_PHYSMEM_BITS       40
+#define MAX_PHYSMEM_BITS       48
 #define SECTION_SIZE_BITS      30
 #endif
 
index 4bc95d27e0636f785383ce222fdcc7adc3073d6a..6d2bf419431d86aece4a3aa0650091f120d3efcd 100644 (file)
@@ -41,7 +41,7 @@
 #define __ARM_NR_compat_cacheflush     (__ARM_NR_COMPAT_BASE+2)
 #define __ARM_NR_compat_set_tls                (__ARM_NR_COMPAT_BASE+5)
 
-#define __NR_compat_syscalls           383
+#define __NR_compat_syscalls           386
 #endif
 
 #define __ARCH_WANT_SYS_CLONE
index e242600c4046c87e1cd554bdb55d02a16fc5f0f4..da1f06b535e38a97bbd981ade5c414d1131ef4e8 100644 (file)
@@ -787,3 +787,8 @@ __SYSCALL(__NR_sched_setattr, sys_sched_setattr)
 __SYSCALL(__NR_sched_getattr, sys_sched_getattr)
 #define __NR_renameat2 382
 __SYSCALL(__NR_renameat2, sys_renameat2)
+                       /* 383 for seccomp */
+#define __NR_getrandom 384
+__SYSCALL(__NR_getrandom, sys_getrandom)
+#define __NR_memfd_create 385
+__SYSCALL(__NR_memfd_create, sys_memfd_create)
index f798f66634afaa1853f6845c75ab6fa9ac09958e..1771696230269673a64606714011b923995353e0 100644 (file)
@@ -49,7 +49,7 @@ static void cpuinfo_detect_icache_policy(struct cpuinfo_arm64 *info)
 
        if (l1ip != ICACHE_POLICY_PIPT)
                set_bit(ICACHEF_ALIASING, &__icache_flags);
-       if (l1ip == ICACHE_POLICY_AIVIVT);
+       if (l1ip == ICACHE_POLICY_AIVIVT)
                set_bit(ICACHEF_AIVIVT, &__icache_flags);
 
        pr_info("Detected %s I-cache on CPU%d\n", icache_policy_str[l1ip], cpu);
index e72f3100958f204ce5b72ba2ce788e2e6cdc3d95..03aaa99e1ea00a3d4caf79d27cea669d857a9090 100644 (file)
@@ -188,6 +188,8 @@ static __init void reserve_regions(void)
                if (uefi_debug)
                        pr_cont("\n");
        }
+
+       set_bit(EFI_MEMMAP, &efi.flags);
 }
 
 
@@ -463,6 +465,8 @@ static int __init arm64_enter_virtual_mode(void)
        efi_native_runtime_setup();
        set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
 
+       efi.runtime_version = efi.systab->hdr.revision;
+
        return 0;
 
 err_unmap:
index ad8aebb1cdef7d289d609015bc22d51498cddc08..3dca15634e69c6b1b34db6e00b3564089129326b 100644 (file)
@@ -270,6 +270,7 @@ static int fpsimd_cpu_pm_notifier(struct notifier_block *self,
        case CPU_PM_ENTER:
                if (current->mm && !test_thread_flag(TIF_FOREIGN_FPSTATE))
                        fpsimd_save_state(&current->thread.fpsimd_state);
+               this_cpu_write(fpsimd_last_state, NULL);
                break;
        case CPU_PM_EXIT:
                if (current->mm)
index 144f10567f82eaa3a6c9a428e3461e08ed911253..873069056229a89c4808b49f73e60d196ff53634 100644 (file)
 
 #define KERNEL_RAM_VADDR       (PAGE_OFFSET + TEXT_OFFSET)
 
-#if (TEXT_OFFSET & 0xf) != 0
-#error TEXT_OFFSET must be at least 16B aligned
-#elif (PAGE_OFFSET & 0xfffff) != 0
+#if (TEXT_OFFSET & 0xfff) != 0
+#error TEXT_OFFSET must be at least 4KB aligned
+#elif (PAGE_OFFSET & 0x1fffff) != 0
 #error PAGE_OFFSET must be at least 2MB aligned
-#elif TEXT_OFFSET > 0xfffff
+#elif TEXT_OFFSET > 0x1fffff
 #error TEXT_OFFSET must be less than 2MB
 #endif
 
@@ -373,10 +373,6 @@ ENTRY(__boot_cpu_mode)
        .long   0
        .popsection
 
-       .align  3
-2:     .quad   .
-       .quad   PAGE_OFFSET
-
 #ifdef CONFIG_SMP
        .align  3
 1:     .quad   .
index 422ebd63b619253d23c7a82d5fb14b322dc47fe1..6762ad705587fa34fff0281546273a6930ddbcbf 100644 (file)
@@ -24,6 +24,12 @@ u64 perf_reg_value(struct pt_regs *regs, int idx)
                        return regs->compat_lr;
        }
 
+       if ((u32)idx == PERF_REG_ARM64_SP)
+               return regs->sp;
+
+       if ((u32)idx == PERF_REG_ARM64_PC)
+               return regs->pc;
+
        return regs->regs[idx];
 }
 
index 0310811bd77d891fe248d0ddb6042af46d3f63ab..fe63ac5e9bf5582cb4e494262a9d714d4b6758a7 100644 (file)
@@ -87,7 +87,8 @@ static void ptrace_hbptriggered(struct perf_event *bp,
                        break;
                }
        }
-       for (i = ARM_MAX_BRP; i < ARM_MAX_HBP_SLOTS && !bp; ++i) {
+
+       for (i = 0; i < ARM_MAX_WRP; ++i) {
                if (current->thread.debug.hbp_watch[i] == bp) {
                        info.si_errno = -((i << 1) + 1);
                        break;
@@ -662,8 +663,10 @@ static int compat_gpr_get(struct task_struct *target,
                        kbuf += sizeof(reg);
                } else {
                        ret = copy_to_user(ubuf, &reg, sizeof(reg));
-                       if (ret)
+                       if (ret) {
+                               ret = -EFAULT;
                                break;
+                       }
 
                        ubuf += sizeof(reg);
                }
@@ -701,8 +704,10 @@ static int compat_gpr_set(struct task_struct *target,
                        kbuf += sizeof(reg);
                } else {
                        ret = copy_from_user(&reg, ubuf, sizeof(reg));
-                       if (ret)
-                               return ret;
+                       if (ret) {
+                               ret = -EFAULT;
+                               break;
+                       }
 
                        ubuf += sizeof(reg);
                }
@@ -1115,19 +1120,15 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs)
        if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
                trace_sys_enter(regs, regs->syscallno);
 
-#ifdef CONFIG_AUDITSYSCALL
        audit_syscall_entry(syscall_get_arch(), regs->syscallno,
                regs->orig_x0, regs->regs[1], regs->regs[2], regs->regs[3]);
-#endif
 
        return regs->syscallno;
 }
 
 asmlinkage void syscall_trace_exit(struct pt_regs *regs)
 {
-#ifdef CONFIG_AUDITSYSCALL
        audit_syscall_exit(regs);
-#endif
 
        if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
                trace_sys_exit(regs, regs_return_value(regs));
index f6f0ccf35ae67110c030d72c6c7648e04168c6e9..edb146d0185740b18de7d7cd365ae5d01ea1cbdc 100644 (file)
@@ -78,6 +78,7 @@ unsigned int compat_elf_hwcap2 __read_mostly;
 #endif
 
 static const char *cpu_name;
+static const char *machine_name;
 phys_addr_t __fdt_pointer __initdata;
 
 /*
@@ -309,6 +310,8 @@ static void __init setup_machine_fdt(phys_addr_t dt_phys)
                while (true)
                        cpu_relax();
        }
+
+       machine_name = of_flat_dt_get_machine_name();
 }
 
 /*
@@ -447,21 +450,10 @@ static int c_show(struct seq_file *m, void *v)
 {
        int i;
 
-       /*
-        * Dump out the common processor features in a single line. Userspace
-        * should read the hwcaps with getauxval(AT_HWCAP) rather than
-        * attempting to parse this.
-        */
-       seq_puts(m, "features\t:");
-       for (i = 0; hwcap_str[i]; i++)
-               if (elf_hwcap & (1 << i))
-                       seq_printf(m, " %s", hwcap_str[i]);
-       seq_puts(m, "\n\n");
+       seq_printf(m, "Processor\t: %s rev %d (%s)\n",
+                  cpu_name, read_cpuid_id() & 15, ELF_PLATFORM);
 
        for_each_online_cpu(i) {
-               struct cpuinfo_arm64 *cpuinfo = &per_cpu(cpu_data, i);
-               u32 midr = cpuinfo->reg_midr;
-
                /*
                 * glibc reads /proc/cpuinfo to determine the number of
                 * online processors, looking for lines beginning with
@@ -470,13 +462,25 @@ static int c_show(struct seq_file *m, void *v)
 #ifdef CONFIG_SMP
                seq_printf(m, "processor\t: %d\n", i);
 #endif
-               seq_printf(m, "implementer\t: 0x%02x\n",
-                          MIDR_IMPLEMENTOR(midr));
-               seq_printf(m, "variant\t\t: 0x%x\n", MIDR_VARIANT(midr));
-               seq_printf(m, "partnum\t\t: 0x%03x\n", MIDR_PARTNUM(midr));
-               seq_printf(m, "revision\t: 0x%x\n\n", MIDR_REVISION(midr));
        }
 
+       /* dump out the processor features */
+       seq_puts(m, "Features\t: ");
+
+       for (i = 0; hwcap_str[i]; i++)
+               if (elf_hwcap & (1 << i))
+                       seq_printf(m, "%s ", hwcap_str[i]);
+
+       seq_printf(m, "\nCPU implementer\t: 0x%02x\n", read_cpuid_id() >> 24);
+       seq_printf(m, "CPU architecture: AArch64\n");
+       seq_printf(m, "CPU variant\t: 0x%x\n", (read_cpuid_id() >> 20) & 15);
+       seq_printf(m, "CPU part\t: 0x%03x\n", (read_cpuid_id() >> 4) & 0xfff);
+       seq_printf(m, "CPU revision\t: %d\n", read_cpuid_id() & 15);
+
+       seq_puts(m, "\n");
+
+       seq_printf(m, "Hardware\t: %s\n", machine_name);
+
        return 0;
 }
 
index e28be510380ca758f8cdb76a5da57892cb02e3bf..34b8bd0711e94295b3b8d629e2e032db8d8bce33 100644 (file)
@@ -66,6 +66,8 @@ static int kvm_handle_wfx(struct kvm_vcpu *vcpu, struct kvm_run *run)
        else
                kvm_vcpu_block(vcpu);
 
+       kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
+
        return 1;
 }
 
index d968796f4b2d7a88dda3605f0f16b9777879052b..c3191168a994fba06b6f5ddc807dbc8eceec224b 100644 (file)
@@ -80,6 +80,10 @@ __do_hyp_init:
        msr     mair_el2, x4
        isb
 
+       /* Invalidate the stale TLBs from Bootloader */
+       tlbi    alle2
+       dsb     sy
+
        mrs     x4, sctlr_el2
        and     x4, x4, #SCTLR_EL2_EE   // preserve endianness of EL2
        ldr     x5, =SCTLR_EL2_FLAGS
index 5b4526ee3a01a6b9c65f15a4985b70cccaf3edea..5472c24018766ea5348d2d0cb56f9a932f46356a 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/of_fdt.h>
 #include <linux/dma-mapping.h>
 #include <linux/dma-contiguous.h>
+#include <linux/efi.h>
 
 #include <asm/fixmap.h>
 #include <asm/sections.h>
@@ -148,7 +149,8 @@ void __init arm64_memblock_init(void)
                memblock_reserve(__virt_to_phys(initrd_start), initrd_end - initrd_start);
 #endif
 
-       early_init_fdt_scan_reserved_mem();
+       if (!efi_enabled(EFI_MEMMAP))
+               early_init_fdt_scan_reserved_mem();
 
        /* 4GB maximum for 32-bit only capable devices */
        if (IS_ENABLED(CONFIG_ZONE_DMA))
index a34f309e580199b5f573db3f975a199cd74d5372..6554e78893f26bc88e96e103811e1f0881a3a5ca 100644 (file)
@@ -129,7 +129,8 @@ unsigned long get_wchan(struct task_struct *p);
 #define        KSTK_EIP(tsk)   ((tsk)->thread.frame0->pc)
 #define        KSTK_ESP(tsk)   ((tsk)->thread.frame0->sp)
 
-#define cpu_relax()    barrier()
+#define cpu_relax() barrier()
+#define cpu_relax_lowlatency() cpu_relax()
 
 /* data cache prefetch */
 #define ARCH_HAS_PREFETCH
index fe14ccf285613c39f8801a8ca29389c5df6afa44..0c76c802e31ce864a0374f3a397a7c403077fec0 100644 (file)
@@ -68,6 +68,7 @@ void flush_icache_range(unsigned long start, unsigned long end)
        );
        local_irq_restore(flags);
 }
+EXPORT_SYMBOL(flush_icache_range);
 
 void hexagon_clean_dcache_range(unsigned long start, unsigned long end)
 {
index 64aefb76bd69054a2f5d9f7627a950347a959d82..c84c88bbbbd79abd66d7cd919bdd7507b0c26b07 100644 (file)
@@ -549,8 +549,6 @@ source "drivers/sn/Kconfig"
 config KEXEC
        bool "kexec system call"
        depends on !IA64_HP_SIM && (!SMP || HOTPLUG_CPU)
-       select CRYPTO
-       select CRYPTO_SHA256
        help
          kexec is a system call that implements the ability to shutdown your
          current kernel, and to start another kernel.  It is like a reboot
index 4254f5d3218c7ed4dc72c9ec2e966b331f3af3c0..10a14ead70b9d9fd627b416c8567008d1aebc606 100644 (file)
@@ -11,7 +11,7 @@
 
 
 
-#define NR_syscalls                    316 /* length of syscall table */
+#define NR_syscalls                    317 /* length of syscall table */
 
 /*
  * The following defines stop scripts/checksyscalls.sh from complaining about
index 99801c3be914afda7f30ccd7fe89306186ad1602..6a65bb7d06571050157bda55a30f9fe366387cbf 100644 (file)
 #define __NR_sched_getattr             1337
 #define __NR_renameat2                 1338
 #define __NR_getrandom                 1339
+#define __NR_memfd_create              1339
 
 #endif /* _UAPI_ASM_IA64_UNISTD_H */
index 4c13837a9269faecf350be25c9bfd10053d86936..01edf242eb296443293fc8b1ee178d72d0a89f55 100644 (file)
@@ -1777,6 +1777,7 @@ sys_call_table:
        data8 sys_sched_getattr
        data8 sys_renameat2
        data8 sys_getrandom
+       data8 sys_memfd_create                  // 1340
 
        .org sys_call_table + 8*NR_syscalls     // guard against failures to increase NR_syscalls
 #endif /* __IA64_ASM_PARAVIRTUALIZED_NATIVE */
index 3ff8c9a25335b20eb4d3f7dfab3513fe584abf39..87b7c7581b1dd5777642a3b87dd9002b7e68dc50 100644 (file)
@@ -91,8 +91,6 @@ config MMU_SUN3
 config KEXEC
        bool "kexec system call"
        depends on M68KCLASSIC
-       select CRYPTO
-       select CRYPTO_SHA256
        help
          kexec is a system call that implements the ability to shutdown your
          current kernel, and to start another kernel.  It is like a reboot
index 1fcdd344c7ad5797605ddbb9ee98bcde3461c295..4ef7a54813e6b72d88a0d40109a26347b91aa7c6 100644 (file)
@@ -4,7 +4,7 @@
 #include <uapi/asm/unistd.h>
 
 
-#define NR_syscalls            352
+#define NR_syscalls            354
 
 #define __ARCH_WANT_OLD_READDIR
 #define __ARCH_WANT_OLD_STAT
index 9cd82fbc7817f716d589368bda3c1d274687a607..b419c6b7ac3739b150000dfd13aff28d3dcc372a 100644 (file)
 #define __NR_sched_setattr     349
 #define __NR_sched_getattr     350
 #define __NR_renameat2         351
+#define __NR_getrandom         352
+#define __NR_memfd_create      353
 
 #endif /* _UAPI_ASM_M68K_UNISTD_H_ */
index 501e102127899c6afaa893bd99d4d555f5bab8ec..05b46c2b08b8d8d4be26c56e8be4d245cef3dab6 100644 (file)
@@ -372,4 +372,6 @@ ENTRY(sys_call_table)
        .long sys_sched_setattr
        .long sys_sched_getattr         /* 350 */
        .long sys_renameat2
+       .long sys_getrandom
+       .long sys_memfd_create
 
index 4e1ddc930a685ef0d6c137d0dc9d165f111acbba..1c2380bf8fe60850274dce0bdbc9e9bb16cc531f 100644 (file)
 #define __NR_sched_setattr     381
 #define __NR_sched_getattr     382
 #define __NR_renameat2         383
+#define __NR_seccomp           384
+#define __NR_getrandom         385
+#define __NR_memfd_create      386
 
 #endif /* _UAPI_ASM_MICROBLAZE_UNISTD_H */
index 1a23d5d5480c7da12bae37f8a77e0015459c4704..de59ee1d7010a788cf916b4ade098375af6214d6 100644 (file)
@@ -384,3 +384,6 @@ ENTRY(sys_call_table)
        .long sys_sched_setattr
        .long sys_sched_getattr
        .long sys_renameat2
+       .long sys_seccomp
+       .long sys_getrandom             /* 385 */
+       .long sys_memfd_create
index df51e78a72cc1b045e5f2e3146be63a5a3ad1790..900c7e5333b650666c374a8e378129b1c7eb43f1 100644 (file)
@@ -2396,8 +2396,6 @@ source "kernel/Kconfig.preempt"
 
 config KEXEC
        bool "Kexec system call"
-       select CRYPTO
-       select CRYPTO_SHA256
        help
          kexec is a system call that implements the ability to shutdown your
          current kernel, and to start another kernel.  It is like a reboot
index 776188908dfc4916c34f73568b1f14467d0f13b8..8c13675a12e74618b64b640f852f30856970fa85 100644 (file)
@@ -847,6 +847,7 @@ int __init db1200_dev_setup(void)
                        pr_warn("DB1200: cant get I2C close to 50MHz\n");
                else
                        clk_set_rate(c, pfc);
+               clk_prepare_enable(c);
                clk_put(c);
        }
 
@@ -922,11 +923,6 @@ int __init db1200_dev_setup(void)
        }
 
        /* Audio PSC clock is supplied externally. (FIXME: platdata!!) */
-       c = clk_get(NULL, "psc1_intclk");
-       if (!IS_ERR(c)) {
-               clk_prepare_enable(c);
-               clk_put(c);
-       }
        __raw_writel(PSC_SEL_CLK_SERCLK,
            (void __iomem *)KSEG1ADDR(AU1550_PSC1_PHYS_ADDR) + PSC_SEL_OFFSET);
        wmb();
index 2b63e7e7d3d35d4414b28cfcecfeacdfed03e458..ad439c27300350ce47ef49e579d0688bc2ca48f4 100644 (file)
@@ -59,12 +59,21 @@ static void bcm47xx_machine_restart(char *command)
        switch (bcm47xx_bus_type) {
 #ifdef CONFIG_BCM47XX_SSB
        case BCM47XX_BUS_TYPE_SSB:
-               ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 3);
+               if (bcm47xx_bus.ssb.chip_id == 0x4785)
+                       write_c0_diag4(1 << 22);
+               ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 1);
+               if (bcm47xx_bus.ssb.chip_id == 0x4785) {
+                       __asm__ __volatile__(
+                               ".set\tmips3\n\t"
+                               "sync\n\t"
+                               "wait\n\t"
+                               ".set\tmips0");
+               }
                break;
 #endif
 #ifdef CONFIG_BCM47XX_BCMA
        case BCM47XX_BUS_TYPE_BCMA:
-               bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc, 3);
+               bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc, 1);
                break;
 #endif
        }
index 008e9c8b8eac0f2ff13edf8f0df7f21172dd6a90..38f4c32e28165543d99bbd391ad3df993789ea06 100644 (file)
@@ -263,7 +263,6 @@ static uint64_t crashk_size, crashk_base;
 static int octeon_uart;
 
 extern asmlinkage void handle_int(void);
-extern asmlinkage void plat_irq_dispatch(void);
 
 /**
  * Return non zero if we are currently running in the Octeon simulator
@@ -458,6 +457,18 @@ static void octeon_halt(void)
        octeon_kill_core(NULL);
 }
 
+static char __read_mostly octeon_system_type[80];
+
+static int __init init_octeon_system_type(void)
+{
+       snprintf(octeon_system_type, sizeof(octeon_system_type), "%s (%s)",
+               cvmx_board_type_to_string(octeon_bootinfo->board_type),
+               octeon_model_get_string(read_c0_prid()));
+
+       return 0;
+}
+early_initcall(init_octeon_system_type);
+
 /**
  * Return a string representing the system type
  *
@@ -465,11 +476,7 @@ static void octeon_halt(void)
  */
 const char *octeon_board_type_string(void)
 {
-       static char name[80];
-       sprintf(name, "%s (%s)",
-               cvmx_board_type_to_string(octeon_bootinfo->board_type),
-               octeon_model_get_string(read_c0_prid()));
-       return name;
+       return octeon_system_type;
 }
 
 const char *get_system_type(void)
diff --git a/arch/mips/include/asm/eva.h b/arch/mips/include/asm/eva.h
new file mode 100644 (file)
index 0000000..a3d1807
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2014, Imagination Technologies Ltd.
+ *
+ * EVA functions for generic code
+ */
+
+#ifndef _ASM_EVA_H
+#define _ASM_EVA_H
+
+#include <kernel-entry-init.h>
+
+#ifdef __ASSEMBLY__
+
+#ifdef CONFIG_EVA
+
+/*
+ * EVA early init code
+ *
+ * Platforms must define their own 'platform_eva_init' macro in
+ * their kernel-entry-init.h header. This macro usually does the
+ * platform specific configuration of the segmentation registers,
+ * and it is normally called from assembly code.
+ *
+ */
+
+.macro eva_init
+platform_eva_init
+.endm
+
+#else
+
+.macro eva_init
+.endm
+
+#endif /* CONFIG_EVA */
+
+#endif /* __ASSEMBLY__ */
+
+#endif
index 3f20b2111d56c3ad8b653f0bbab81d3d14d46ba9..d7699cf7e135e22f84b0f4c5e45028ce5567d404 100644 (file)
@@ -49,7 +49,7 @@
 #endif
 #define GICBIS(reg, mask, bits)                        \
        do { u32 data;                          \
-               GICREAD((reg), data);           \
+               GICREAD(reg, data);             \
                data &= ~(mask);                \
                data |= ((bits) & (mask));      \
                GICWRITE((reg), data);          \
index ae1f7b24dd1a511daa15423dd8186cea9812009c..39f07aec640cf27b865d270e45f34fed6b547274 100644 (file)
@@ -26,6 +26,8 @@ static inline int irq_canonicalize(int irq)
 #define irq_canonicalize(irq) (irq)    /* Sane hardware, sane code ... */
 #endif
 
+asmlinkage void plat_irq_dispatch(void);
+
 extern void do_IRQ(unsigned int irq);
 
 extern void arch_init_irq(void);
index 77eeda77e73c7332f9175ed4706cf18d92d8a5b1..0cf8622db27f4689b9e7bb076b422d67a0c28cf9 100644 (file)
 #ifndef __ASM_MACH_MIPS_KERNEL_ENTRY_INIT_H
 #define __ASM_MACH_MIPS_KERNEL_ENTRY_INIT_H
 
+#include <asm/regdef.h>
+#include <asm/mipsregs.h>
+
        /*
         * Prepare segments for EVA boot:
         *
         * This is in case the processor boots in legacy configuration
         * (SI_EVAReset is de-asserted and CONFIG5.K == 0)
         *
-        * On entry, t1 is loaded with CP0_CONFIG
-        *
         * ========================= Mappings =============================
         * Virtual memory           Physical memory           Mapping
         * 0x00000000 - 0x7fffffff  0x80000000 - 0xfffffffff   MUSUK (kuseg)
         *
         *
         * Lowmem is expanded to 2GB
+        *
+        * The following code uses the t0, t1, t2 and ra registers without
+        * previously preserving them.
+        *
         */
-       .macro  eva_entry
+       .macro  platform_eva_init
+
+       .set    push
+       .set    reorder
        /*
         * Get Config.K0 value and use it to program
         * the segmentation registers
         */
+       mfc0    t1, CP0_CONFIG
        andi    t1, 0x7 /* CCA */
        move    t2, t1
        ins     t2, t1, 16, 3
@@ -77,6 +86,8 @@
        mtc0    t0, $16, 5
        sync
        jal     mips_ihb
+
+       .set    pop
        .endm
 
        .macro  kernel_entry_setup
        sll     t0, t0, 6   /* SC bit */
        bgez    t0, 9f
 
-       eva_entry
+       platform_eva_init
        b       0f
 9:
        /* Assume we came from YAMON... */
@@ -127,8 +138,7 @@ nonsc_processor:
 #ifdef CONFIG_EVA
        sync
        ehb
-       mfc0    t1, CP0_CONFIG
-       eva_entry
+       platform_eva_init
 #endif
        .endm
 
index ceeb1f5e7129b0692a088d673444359106bb264d..0eb43c832b2546d9254278be6ef53273f2a1ff4b 100644 (file)
 
 #include <asm/mach-netlogic/multi-node.h>
 
-#ifdef CONFIG_SMP
-#define topology_physical_package_id(cpu)      cpu_to_node(cpu)
-#define topology_core_id(cpu)  (cpu_logical_map(cpu) / NLM_THREADS_PER_CORE)
-#define topology_thread_cpumask(cpu)           (&cpu_sibling_map[cpu])
-#define topology_core_cpumask(cpu)     cpumask_of_node(cpu_to_node(cpu))
-#endif
-
 #include <asm-generic/topology.h>
 
 #endif /* _ASM_MACH_NETLOGIC_TOPOLOGY_H */
index 027c74db13f94399ea8a99088ee9095725b1fe75..df49a308085caa568c74e48a64a1eea0d7f2b845 100644 (file)
@@ -122,6 +122,9 @@ do {                                                                        \
        }                                                               \
 } while(0)
 
+extern void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep,
+       pte_t pteval);
+
 #if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32)
 
 #define pte_none(pte)          (!(((pte).pte_low | (pte).pte_high) & ~_PAGE_GLOBAL))
@@ -145,7 +148,6 @@ static inline void set_pte(pte_t *ptep, pte_t pte)
                }
        }
 }
-#define set_pte_at(mm, addr, ptep, pteval) set_pte(ptep, pteval)
 
 static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
@@ -183,7 +185,6 @@ static inline void set_pte(pte_t *ptep, pte_t pteval)
        }
 #endif
 }
-#define set_pte_at(mm, addr, ptep, pteval) set_pte(ptep, pteval)
 
 static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
@@ -390,15 +391,12 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 
 extern void __update_tlb(struct vm_area_struct *vma, unsigned long address,
        pte_t pte);
-extern void __update_cache(struct vm_area_struct *vma, unsigned long address,
-       pte_t pte);
 
 static inline void update_mmu_cache(struct vm_area_struct *vma,
        unsigned long address, pte_t *ptep)
 {
        pte_t pte = *ptep;
        __update_tlb(vma, address, pte);
-       __update_cache(vma, address, pte);
 }
 
 static inline void update_mmu_cache_pmd(struct vm_area_struct *vma,
index 17960fe7a8ce4ef21b7a94cca10c7b5af61cec17..cdf68b33bd65ac5826ac369a4d06aeedc3d1fd90 100644 (file)
@@ -131,10 +131,12 @@ static inline int syscall_get_arch(void)
 {
        int arch = EM_MIPS;
 #ifdef CONFIG_64BIT
-       if (!test_thread_flag(TIF_32BIT_REGS))
+       if (!test_thread_flag(TIF_32BIT_REGS)) {
                arch |= __AUDIT_ARCH_64BIT;
-       if (test_thread_flag(TIF_32BIT_ADDR))
-               arch |= __AUDIT_ARCH_CONVENTION_MIPS64_N32;
+               /* N32 sets only TIF_32BIT_ADDR */
+               if (test_thread_flag(TIF_32BIT_ADDR))
+                       arch |= __AUDIT_ARCH_CONVENTION_MIPS64_N32;
+       }
 #endif
 #if defined(__LITTLE_ENDIAN)
        arch |=  __AUDIT_ARCH_LE;
index 6f4f739dad9635521eb0c8697365a3efd69f28eb..e6e97d2a5c9e68cccde81ab0f181184d1e27fd13 100644 (file)
@@ -13,6 +13,7 @@
 #include <asm/asm-offsets.h>
 #include <asm/asmmacro.h>
 #include <asm/cacheops.h>
+#include <asm/eva.h>
 #include <asm/mipsregs.h>
 #include <asm/mipsmtregs.h>
 #include <asm/pm.h>
@@ -166,6 +167,9 @@ dcache_done:
 1:     jal     mips_cps_core_init
         nop
 
+       /* Do any EVA initialization if necessary */
+       eva_init
+
        /*
         * Boot any other VPEs within this core that should be online, and
         * deactivate this VPE if it should be offline.
index 14bf74b0f51c066f488caba872ebdaddd8caefe8..b63f2482f2881c24a3d62d2f95ca9a2eb5cf2799 100644 (file)
@@ -558,7 +558,7 @@ static int mipspmu_get_irq(void)
        if (mipspmu.irq >= 0) {
                /* Request my own irq handler. */
                err = request_irq(mipspmu.irq, mipsxx_pmu_handle_irq,
-                       IRQF_PERCPU | IRQF_NOBALANCING,
+                       IRQF_PERCPU | IRQF_NOBALANCING | IRQF_NO_THREAD,
                        "mips_perf_pmu", NULL);
                if (err) {
                        pr_warning("Unable to request IRQ%d for MIPS "
index 13b964fddc4a9e15e4bdc8fbfd2f7312a04a59ca..25bb8400156da3905d1ba2d586da26a4672b4379 100644 (file)
@@ -113,15 +113,19 @@ trace_a_syscall:
        move    s0, t2                  # Save syscall pointer
        move    a0, sp
        /*
-        * syscall number is in v0 unless we called syscall(__NR_###)
+        * absolute syscall number is in v0 unless we called syscall(__NR_###)
         * where the real syscall number is in a0
         * note: NR_syscall is the first O32 syscall but the macro is
         * only defined when compiling with -mabi=32 (CONFIG_32BIT)
         * therefore __NR_O32_Linux is used (4000)
         */
-       addiu   a1, v0,  __NR_O32_Linux
-       bnez    v0, 1f /* __NR_syscall at offset 0 */
-       lw      a1, PT_R4(sp)
+       .set    push
+       .set    reorder
+       subu    t1, v0,  __NR_O32_Linux
+       move    a1, v0
+       bnez    t1, 1f /* __NR_syscall at offset 0 */
+       lw      a1, PT_R4(sp) /* Arg1 for __NR_syscall case */
+       .set    pop
 
 1:     jal     syscall_trace_enter
 
index 9182e8d2967c774ff39456968d07d832773fe362..b03e37d2071ac867e65a702f7e052a00c13f496c 100644 (file)
 static int loongson_cu2_call(struct notifier_block *nfb, unsigned long action,
        void *data)
 {
-       int fpu_enabled;
+       int fpu_owned;
        int fr = !test_thread_flag(TIF_32BIT_FPREGS);
 
        switch (action) {
        case CU2_EXCEPTION:
                preempt_disable();
-               fpu_enabled = read_c0_status() & ST0_CU1;
+               fpu_owned = __is_fpu_owner();
                if (!fr)
                        set_c0_status(ST0_CU1 | ST0_CU2);
                else
@@ -39,8 +39,8 @@ static int loongson_cu2_call(struct notifier_block *nfb, unsigned long action,
                        KSTK_STATUS(current) |= ST0_FR;
                else
                        KSTK_STATUS(current) &= ~ST0_FR;
-               /* If FPU is enabled, we needn't init or restore fp */
-               if(!fpu_enabled) {
+               /* If FPU is owned, we needn't init or restore fp */
+               if (!fpu_owned) {
                        set_thread_flag(TIF_USEDFPU);
                        if (!used_math()) {
                                _init_fpu();
index ca025a6ba559bbe644e555290af2a617fd90d9ce..37ed184398c6bbf8d017f130c73317ed2e548518 100644 (file)
@@ -24,8 +24,6 @@
 #include <asm/page.h>
 #include <asm/pgalloc.h>
 #include <asm/sections.h>
-#include <linux/bootmem.h>
-#include <linux/init.h>
 #include <linux/irq.h>
 #include <asm/bootinfo.h>
 #include <asm/mc146818-time.h>
index f7b91d3a371dd07e7c69c38290f1f0c77b5b3a0a..7e3ea77668224ff3da82eed073721a203b1a0588 100644 (file)
@@ -119,25 +119,36 @@ void __flush_anon_page(struct page *page, unsigned long vmaddr)
 
 EXPORT_SYMBOL(__flush_anon_page);
 
-void __update_cache(struct vm_area_struct *vma, unsigned long address,
-       pte_t pte)
+static void mips_flush_dcache_from_pte(pte_t pteval, unsigned long address)
 {
        struct page *page;
-       unsigned long pfn, addr;
-       int exec = (vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc;
+       unsigned long pfn = pte_pfn(pteval);
 
-       pfn = pte_pfn(pte);
        if (unlikely(!pfn_valid(pfn)))
                return;
+
        page = pfn_to_page(pfn);
        if (page_mapping(page) && Page_dcache_dirty(page)) {
-               addr = (unsigned long) page_address(page);
-               if (exec || pages_do_alias(addr, address & PAGE_MASK))
-                       flush_data_cache_page(addr);
+               unsigned long page_addr = (unsigned long) page_address(page);
+
+               if (!cpu_has_ic_fills_f_dc ||
+                   pages_do_alias(page_addr, address & PAGE_MASK))
+                       flush_data_cache_page(page_addr);
                ClearPageDcacheDirty(page);
        }
 }
 
+void set_pte_at(struct mm_struct *mm, unsigned long addr,
+        pte_t *ptep, pte_t pteval)
+{
+        if (cpu_has_dc_aliases || !cpu_has_ic_fills_f_dc) {
+                if (pte_present(pteval))
+                        mips_flush_dcache_from_pte(pteval, addr);
+        }
+
+        set_pte(ptep, pteval);
+}
+
 unsigned long _page_cachable_default;
 EXPORT_SYMBOL(_page_cachable_default);
 
index 0c35dee0a2150b4ca284a03dd3637cad6eb77b86..8fddd2cdbff72920cb7a9c73154a7b95413fb306 100644 (file)
@@ -35,13 +35,19 @@ fw_memblock_t * __init fw_getmdesc(int eva)
        /* otherwise look in the environment */
 
        memsize_str = fw_getenv("memsize");
-       if (memsize_str)
-               tmp = kstrtol(memsize_str, 0, &memsize);
+       if (memsize_str) {
+               tmp = kstrtoul(memsize_str, 0, &memsize);
+               if (tmp)
+                       pr_warn("Failed to read the 'memsize' env variable.\n");
+       }
        if (eva) {
        /* Look for ememsize for EVA */
                ememsize_str = fw_getenv("ememsize");
-               if (ememsize_str)
-                       tmp = kstrtol(ememsize_str, 0, &ememsize);
+               if (ememsize_str) {
+                       tmp = kstrtoul(ememsize_str, 0, &ememsize);
+                       if (tmp)
+                               pr_warn("Failed to read the 'ememsize' env variable.\n");
+               }
        }
        if (!memsize && !ememsize) {
                pr_warn("memsize not set in YAMON, set to default (32Mb)\n");
index 05a56619ece2f72044641c6aa1fd2d99f558bb69..0e97ccd29fe3a6fe37b1b0053b531ccb6149f654 100644 (file)
@@ -1417,7 +1417,7 @@ void bpf_jit_compile(struct bpf_prog *fp)
                bpf_jit_dump(fp->len, alloc_size, 2, ctx.target);
 
        fp->bpf_func = (void *)ctx.target;
-       fp->jited = 1;
+       fp->jited = true;
 
 out:
        kfree(ctx.offsets);
@@ -1427,5 +1427,6 @@ void bpf_jit_free(struct bpf_prog *fp)
 {
        if (fp->jited)
                module_free(NULL, fp->bpf_func);
-       kfree(fp);
+
+       bpf_prog_unlock_free(fp);
 }
index 941744aabb513dd3ad69fc3a44c4dbd804e9f744..f914c753de21dcc9982a3f13ec007db9069d42a4 100644 (file)
@@ -51,7 +51,7 @@ static inline void sec_int_dispatch(void)  { do_IRQ(MSP_INT_SEC);  }
  * the range 40-71.
  */
 
-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+asmlinkage void plat_irq_dispatch(void)
 {
        u32 pending;
 
index a577609f8ed60229ed4d3fc26931bc23f955c599..4bc7b62fb4b68761341619d7bd8300dbb8786d76 100644 (file)
@@ -399,8 +399,6 @@ config PPC64_SUPPORTS_MEMORY_FAILURE
 config KEXEC
        bool "kexec system call"
        depends on (PPC_BOOK3S || FSL_BOOKE || (44x && !SMP))
-       select CRYPTO
-       select CRYPTO_SHA256
        help
          kexec is a system call that implements the ability to shutdown your
          current kernel, and to start another kernel.  It is like a reboot
index 72c20bb16d266b4ed0aa2160382414f161ad0663..79294c4c5015ea83771e4ebc849a561bd376144d 100644 (file)
@@ -62,10 +62,10 @@ long kvmppc_alloc_hpt(struct kvm *kvm, u32 *htab_orderp)
        }
 
        kvm->arch.hpt_cma_alloc = 0;
-       page = kvm_alloc_hpt(1 << (order - PAGE_SHIFT));
+       page = kvm_alloc_hpt(1ul << (order - PAGE_SHIFT));
        if (page) {
                hpt = (unsigned long)pfn_to_kaddr(page_to_pfn(page));
-               memset((void *)hpt, 0, (1 << order));
+               memset((void *)hpt, 0, (1ul << order));
                kvm->arch.hpt_cma_alloc = 1;
        }
 
index 329d7fdd0a6ab7be8b9e203ac53b1870c1d37b0c..b9615ba5b083a6ddeea76b878925396561b5fb42 100644 (file)
@@ -101,7 +101,7 @@ struct kvm_rma_info *kvm_alloc_rma()
        ri = kmalloc(sizeof(struct kvm_rma_info), GFP_KERNEL);
        if (!ri)
                return NULL;
-       page = cma_alloc(kvm_cma, kvm_rma_pages, get_order(kvm_rma_pages));
+       page = cma_alloc(kvm_cma, kvm_rma_pages, order_base_2(kvm_rma_pages));
        if (!page)
                goto err_out;
        atomic_set(&ri->use_count, 1);
@@ -135,12 +135,12 @@ struct page *kvm_alloc_hpt(unsigned long nr_pages)
 {
        unsigned long align_pages = HPT_ALIGN_PAGES;
 
-       VM_BUG_ON(get_order(nr_pages) < KVM_CMA_CHUNK_ORDER - PAGE_SHIFT);
+       VM_BUG_ON(order_base_2(nr_pages) < KVM_CMA_CHUNK_ORDER - PAGE_SHIFT);
 
        /* Old CPUs require HPT aligned on a multiple of its size */
        if (!cpu_has_feature(CPU_FTR_ARCH_206))
                align_pages = nr_pages;
-       return cma_alloc(kvm_cma, nr_pages, get_order(align_pages));
+       return cma_alloc(kvm_cma, nr_pages, order_base_2(align_pages));
 }
 EXPORT_SYMBOL_GPL(kvm_alloc_hpt);
 
index 3afa6f4c195705569726ef927ddc8f392af097ac..cbae2dfd053cafc22540572652528d4dbedc91fe 100644 (file)
@@ -686,7 +686,7 @@ void bpf_jit_compile(struct bpf_prog *fp)
                ((u64 *)image)[0] = (u64)code_base;
                ((u64 *)image)[1] = local_paca->kernel_toc;
                fp->bpf_func = (void *)image;
-               fp->jited = 1;
+               fp->jited = true;
        }
 out:
        kfree(addrs);
@@ -697,5 +697,6 @@ void bpf_jit_free(struct bpf_prog *fp)
 {
        if (fp->jited)
                module_free(NULL, fp->bpf_func);
-       kfree(fp);
+
+       bpf_prog_unlock_free(fp);
 }
index ab39ceb89ecfa3e4b8e1b3eb34e3787aedbefeaa..05c78bb5f57024bf220e778af99888a1df6e6bbc 100644 (file)
@@ -48,8 +48,6 @@ config ARCH_SUPPORTS_DEBUG_PAGEALLOC
 
 config KEXEC
        def_bool y
-       select CRYPTO
-       select CRYPTO_SHA256
 
 config AUDIT_ARCH
        def_bool y
index b76317c1f3eb5b542d3ee628326da48910866770..5efb2fe186e78275faa6ecc223b94a8c96c86a70 100644 (file)
@@ -1127,7 +1127,7 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
                                            unsigned long addr, pte_t *ptep)
 {
        pgste_t pgste;
-       pte_t pte;
+       pte_t pte, oldpte;
        int young;
 
        if (mm_has_pgste(vma->vm_mm)) {
@@ -1135,12 +1135,13 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
                pgste = pgste_ipte_notify(vma->vm_mm, ptep, pgste);
        }
 
-       pte = *ptep;
+       oldpte = pte = *ptep;
        ptep_flush_direct(vma->vm_mm, addr, ptep);
        young = pte_young(pte);
        pte = pte_mkold(pte);
 
        if (mm_has_pgste(vma->vm_mm)) {
+               pgste = pgste_update_all(&oldpte, pgste, vma->vm_mm);
                pgste = pgste_set_pte(ptep, pgste, pte);
                pgste_set_unlock(ptep, pgste);
        } else
@@ -1330,6 +1331,7 @@ static inline int ptep_set_access_flags(struct vm_area_struct *vma,
        ptep_flush_direct(vma->vm_mm, address, ptep);
 
        if (mm_has_pgste(vma->vm_mm)) {
+               pgste_set_key(ptep, pgste, entry, vma->vm_mm);
                pgste = pgste_set_pte(ptep, pgste, entry);
                pgste_set_unlock(ptep, pgste);
        } else
index 3802d2d3a18d7cf4abf5604d6f66e01b6e34424d..940ac49198db1dd406b99944f51183df869cd420 100644 (file)
 #define __NR_sched_setattr     345
 #define __NR_sched_getattr     346
 #define __NR_renameat2         347
-#define NR_syscalls 348
+#define __NR_seccomp           348
+#define __NR_getrandom         349
+#define __NR_memfd_create      350
+#define NR_syscalls 351
 
 /* 
  * There are some system calls that are not present on 64 bit, some
index 45cdb37aa6f812813c69d08102e4e1f521e5df1f..faf6caa510dcedb862ad65be7108e1042a754939 100644 (file)
@@ -214,3 +214,6 @@ COMPAT_SYSCALL_WRAP3(finit_module, int, fd, const char __user *, uargs, int, fla
 COMPAT_SYSCALL_WRAP3(sched_setattr, pid_t, pid, struct sched_attr __user *, attr, unsigned int, flags);
 COMPAT_SYSCALL_WRAP4(sched_getattr, pid_t, pid, struct sched_attr __user *, attr, unsigned int, size, unsigned int, flags);
 COMPAT_SYSCALL_WRAP5(renameat2, int, olddfd, const char __user *, oldname, int, newdfd, const char __user *, newname, unsigned int, flags);
+COMPAT_SYSCALL_WRAP3(seccomp, unsigned int, op, unsigned int, flags, const char __user *, uargs)
+COMPAT_SYSCALL_WRAP3(getrandom, char __user *, buf, size_t, count, unsigned int, flags)
+COMPAT_SYSCALL_WRAP2(memfd_create, const char __user *, uname, unsigned int, flags)
index 633ca7504536c10a517667b5f582653f763390e3..22aac5885ba23eca4590d9219aefc1fab34d9325 100644 (file)
@@ -2060,6 +2060,13 @@ void s390_reset_system(void (*func)(void *), void *data)
        S390_lowcore.program_new_psw.addr =
                PSW_ADDR_AMODE | (unsigned long) s390_base_pgm_handler;
 
+       /*
+        * Clear subchannel ID and number to signal new kernel that no CCW or
+        * SCSI IPL has been done (for kexec and kdump)
+        */
+       S390_lowcore.subchannel_id = 0;
+       S390_lowcore.subchannel_nr = 0;
+
        /* Store status at absolute zero */
        store_status();
 
index ae1d5be7dd885d4d20f7b1f37d56ebbab9f92526..82bc113e8c1dd3718cf663a88d7bc9a2c9c97fb4 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/stddef.h>
 #include <linux/unistd.h>
 #include <linux/ptrace.h>
+#include <linux/random.h>
 #include <linux/user.h>
 #include <linux/tty.h>
 #include <linux/ioport.h>
@@ -61,6 +62,7 @@
 #include <asm/diag.h>
 #include <asm/os_info.h>
 #include <asm/sclp.h>
+#include <asm/sysinfo.h>
 #include "entry.h"
 
 /*
@@ -766,6 +768,7 @@ static void __init setup_hwcaps(void)
 #endif
 
        get_cpu_id(&cpu_id);
+       add_device_randomness(&cpu_id, sizeof(cpu_id));
        switch (cpu_id.machine) {
        case 0x9672:
 #if !defined(CONFIG_64BIT)
@@ -803,6 +806,19 @@ static void __init setup_hwcaps(void)
        }
 }
 
+/*
+ * Add system information as device randomness
+ */
+static void __init setup_randomness(void)
+{
+       struct sysinfo_3_2_2 *vmms;
+
+       vmms = (struct sysinfo_3_2_2 *) alloc_page(GFP_KERNEL);
+       if (vmms && stsi(vmms, 3, 2, 2) == 0 && vmms->count)
+               add_device_randomness(&vmms, vmms->count);
+       free_page((unsigned long) vmms);
+}
+
 /*
  * Setup function called from init/main.c just after the banner
  * was printed.
@@ -901,6 +917,9 @@ void __init setup_arch(char **cmdline_p)
 
        /* Setup zfcpdump support */
        setup_zfcpdump();
+
+       /* Add system specific data to the random pool */
+       setup_randomness();
 }
 
 #ifdef CONFIG_32BIT
index fe5cdf29a001be0e52fd0436bbbabd3603d37f66..6fe886ac2db596a81f67a80e69e4f5f54609c45f 100644 (file)
@@ -356,3 +356,6 @@ SYSCALL(sys_finit_module,sys_finit_module,compat_sys_finit_module)
 SYSCALL(sys_sched_setattr,sys_sched_setattr,compat_sys_sched_setattr) /* 345 */
 SYSCALL(sys_sched_getattr,sys_sched_getattr,compat_sys_sched_getattr)
 SYSCALL(sys_renameat2,sys_renameat2,compat_sys_renameat2)
+SYSCALL(sys_seccomp,sys_seccomp,compat_sys_seccomp)
+SYSCALL(sys_getrandom,sys_getrandom,compat_sys_getrandom)
+SYSCALL(sys_memfd_create,sys_memfd_create,compat_sys_memfd_create) /* 350 */
index ce81eb2ab76a207128069119acaac4e92918fa99..81b0e11521e444501ff5b1fc723965374ea3bd7e 100644 (file)
@@ -1317,19 +1317,6 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
                return -EINVAL;
        }
 
-       switch (kvm_run->exit_reason) {
-       case KVM_EXIT_S390_SIEIC:
-       case KVM_EXIT_UNKNOWN:
-       case KVM_EXIT_INTR:
-       case KVM_EXIT_S390_RESET:
-       case KVM_EXIT_S390_UCONTROL:
-       case KVM_EXIT_S390_TSCH:
-       case KVM_EXIT_DEBUG:
-               break;
-       default:
-               BUG();
-       }
-
        vcpu->arch.sie_block->gpsw.mask = kvm_run->psw_mask;
        vcpu->arch.sie_block->gpsw.addr = kvm_run->psw_addr;
        if (kvm_run->kvm_dirty_regs & KVM_SYNC_PREFIX) {
index 19daa53a3da4a739f8f1b89cb7b88bf4dc0e5606..5404a6261db91a4fa204a9e2ad839b97530604c7 100644 (file)
@@ -986,11 +986,21 @@ int set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
        pte_t *ptep;
 
        down_read(&mm->mmap_sem);
+retry:
        ptep = get_locked_pte(current->mm, addr, &ptl);
        if (unlikely(!ptep)) {
                up_read(&mm->mmap_sem);
                return -EFAULT;
        }
+       if (!(pte_val(*ptep) & _PAGE_INVALID) &&
+            (pte_val(*ptep) & _PAGE_PROTECT)) {
+                       pte_unmap_unlock(*ptep, ptl);
+                       if (fixup_user_fault(current, mm, addr, FAULT_FLAG_WRITE)) {
+                               up_read(&mm->mmap_sem);
+                               return -EFAULT;
+                       }
+                       goto retry;
+               }
 
        new = old = pgste_get_lock(ptep);
        pgste_val(new) &= ~(PGSTE_GR_BIT | PGSTE_GC_BIT |
index 61e45b7c04d7bdf122a195903face00cfb6c2ce3..555f5c7e83abfd4e9e62477274ac888f7280092e 100644 (file)
@@ -5,11 +5,9 @@
  *
  * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
  */
-#include <linux/moduleloader.h>
 #include <linux/netdevice.h>
 #include <linux/if_vlan.h>
 #include <linux/filter.h>
-#include <linux/random.h>
 #include <linux/init.h>
 #include <asm/cacheflush.h>
 #include <asm/facility.h>
@@ -148,6 +146,12 @@ struct bpf_jit {
        ret;                                            \
 })
 
+static void bpf_jit_fill_hole(void *area, unsigned int size)
+{
+       /* Fill whole space with illegal instructions */
+       memset(area, 0, size);
+}
+
 static void bpf_jit_prologue(struct bpf_jit *jit)
 {
        /* Save registers and create stack frame if necessary */
@@ -780,38 +784,6 @@ out:
        return -1;
 }
 
-/*
- * Note: for security reasons, bpf code will follow a randomly
- *      sized amount of illegal instructions.
- */
-struct bpf_binary_header {
-       unsigned int pages;
-       u8 image[];
-};
-
-static struct bpf_binary_header *bpf_alloc_binary(unsigned int bpfsize,
-                                                 u8 **image_ptr)
-{
-       struct bpf_binary_header *header;
-       unsigned int sz, hole;
-
-       /* Most BPF filters are really small, but if some of them fill a page,
-        * allow at least 128 extra bytes for illegal instructions.
-        */
-       sz = round_up(bpfsize + sizeof(*header) + 128, PAGE_SIZE);
-       header = module_alloc(sz);
-       if (!header)
-               return NULL;
-       memset(header, 0, sz);
-       header->pages = sz / PAGE_SIZE;
-       hole = min(sz - (bpfsize + sizeof(*header)), PAGE_SIZE - sizeof(*header));
-       /* Insert random number of illegal instructions before BPF code
-        * and make sure the first instruction starts at an even address.
-        */
-       *image_ptr = &header->image[(prandom_u32() % hole) & -2];
-       return header;
-}
-
 void bpf_jit_compile(struct bpf_prog *fp)
 {
        struct bpf_binary_header *header = NULL;
@@ -850,7 +822,8 @@ void bpf_jit_compile(struct bpf_prog *fp)
                        size = prg_len + lit_len;
                        if (size >= BPF_SIZE_MAX)
                                goto out;
-                       header = bpf_alloc_binary(size, &jit.start);
+                       header = bpf_jit_binary_alloc(size, &jit.start,
+                                                     2, bpf_jit_fill_hole);
                        if (!header)
                                goto out;
                        jit.prg = jit.mid = jit.start + prg_len;
@@ -869,7 +842,7 @@ void bpf_jit_compile(struct bpf_prog *fp)
        if (jit.start) {
                set_memory_ro((unsigned long)header, header->pages);
                fp->bpf_func = (void *) jit.start;
-               fp->jited = 1;
+               fp->jited = true;
        }
 out:
        kfree(addrs);
@@ -884,8 +857,8 @@ void bpf_jit_free(struct bpf_prog *fp)
                goto free_filter;
 
        set_memory_rw(addr, header->pages);
-       module_free(NULL, header);
+       bpf_jit_binary_free(header);
 
 free_filter:
-       kfree(fp);
+       bpf_prog_unlock_free(fp);
 }
index 453fa5c09550c592a9dae8c6dc7c24ebbbded80f..244fb4c81e2525d0cbc62dceab964722bff5b5c5 100644 (file)
@@ -172,6 +172,7 @@ menu "System type"
 #
 config CPU_SH2
        bool
+       select SH_INTC
 
 config CPU_SH2A
        bool
@@ -182,6 +183,7 @@ config CPU_SH3
        bool
        select CPU_HAS_INTEVT
        select CPU_HAS_SR_RB
+       select SH_INTC
        select SYS_SUPPORTS_SH_TMU
 
 config CPU_SH4
@@ -189,6 +191,7 @@ config CPU_SH4
        select CPU_HAS_INTEVT
        select CPU_HAS_SR_RB
        select CPU_HAS_FPU if !CPU_SH4AL_DSP
+       select SH_INTC
        select SYS_SUPPORTS_SH_TMU
        select SYS_SUPPORTS_HUGETLBFS if MMU
 
@@ -595,8 +598,6 @@ source kernel/Kconfig.hz
 config KEXEC
        bool "kexec system call (EXPERIMENTAL)"
        depends on SUPERH32 && MMU
-       select CRYPTO
-       select CRYPTO_SHA256
        help
          kexec is a system call that implements the ability to shutdown your
          current kernel, and to start another kernel.  It is like a reboot
index 097c2cdd117f53c543fb919ba6740210b1471a4a..f770e3992620e8a1673ee1a2bd47280be55cccd4 100644 (file)
@@ -229,6 +229,7 @@ void flush_icache_range(unsigned long start, unsigned long end)
 
        cacheop_on_each_cpu(local_flush_icache_range, (void *)&data, 1);
 }
+EXPORT_SYMBOL(flush_icache_range);
 
 void flush_icache_page(struct vm_area_struct *vma, struct page *page)
 {
index 1f76c22a6a75d64a5dafd6f24da19eec6c816e96..b2ad9dc5425e261fd580232aff0b22b763542d99 100644 (file)
@@ -801,7 +801,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;
+               fp->jited = true;
        }
 out:
        kfree(addrs);
@@ -812,5 +812,6 @@ void bpf_jit_free(struct bpf_prog *fp)
 {
        if (fp->jited)
                module_free(NULL, fp->bpf_func);
-       kfree(fp);
+
+       bpf_prog_unlock_free(fp);
 }
index a3ffe2dd4832b18ff60e2716e770e1dfb7324d44..7fcd492adbfcfb030a34c2f4d34558fc9a20ad81 100644 (file)
@@ -191,8 +191,6 @@ source "kernel/Kconfig.hz"
 
 config KEXEC
        bool "kexec system call"
-       select CRYPTO
-       select CRYPTO_SHA256
        ---help---
          kexec is a system call that implements the ability to shutdown your
          current kernel, and to start another kernel.  It is like a reboot
index 01e8ab29f43a8bac34f3d0f98ea6e8c2b69cd2df..19eaa62d456a7c0635c9ec407dc3b998b7027bd4 100644 (file)
@@ -183,6 +183,7 @@ void flush_icache_range(unsigned long start, unsigned long end)
                preempt_enable();
        }
 }
+EXPORT_SYMBOL(flush_icache_range);
 
 
 /* Called when smp_send_reschedule() triggers IRQ_RESCHEDULE. */
index 780d77388dec507d7e11bb6f9d8595fe4f64c93d..7c8fb7018dc6bf728a5a70ef9bde100d94f3b565 100644 (file)
@@ -254,7 +254,8 @@ static int setup_frame(struct ksignal *ksig, sigset_t *set,
 
        err |= setup_sigframe(frame, regs, set);
        if (err == 0)
-               err |= setup_return(regs, &ksig->ka, frame->retcode, frame, usig);
+               err |= setup_return(regs, &ksig->ka, frame->retcode, frame,
+                                   ksig->sig);
 
        return err;
 }
@@ -276,7 +277,8 @@ static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
        err |= __save_altstack(&frame->sig.uc.uc_stack, regs->UCreg_sp);
        err |= setup_sigframe(&frame->sig, regs, set);
        if (err == 0)
-               err |= setup_return(regs, &ksig->ka, frame->sig.retcode, frame, usig);
+               err |= setup_return(regs, &ksig->ka, frame->sig.retcode, frame,
+                                   ksig->sig);
 
        if (err == 0) {
                /*
@@ -303,7 +305,6 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs,
                          int syscall)
 {
        struct thread_info *thread = current_thread_info();
-       struct task_struct *tsk = current;
        sigset_t *oldset = sigmask_to_save();
        int usig = ksig->sig;
        int ret;
@@ -373,7 +374,7 @@ static void do_signal(struct pt_regs *regs, int syscall)
        if (!user_mode(regs))
                return;
 
-       if (get_signsl(&ksig)) {
+       if (get_signal(&ksig)) {
                handle_signal(&ksig, regs, syscall);
                return;
        }
index 61b6d51866f8680353044f5d7f5a3ea5cb19b7ac..3942f74c92d7d338ee0c8a858ad2e5a81774686d 100644 (file)
@@ -17,6 +17,4 @@ obj-$(CONFIG_IA32_EMULATION) += ia32/
 obj-y += platform/
 obj-y += net/
 
-ifeq ($(CONFIG_X86_64),y)
-obj-$(CONFIG_KEXEC) += purgatory/
-endif
+obj-$(CONFIG_KEXEC_FILE) += purgatory/
index 5d0bf1aa9dcb6d68fd39f395dcbef9f89954cbc0..778178f4c7d132c15f4f7700b0ad31a20ea7d24b 100644 (file)
@@ -1585,9 +1585,6 @@ source kernel/Kconfig.hz
 
 config KEXEC
        bool "kexec system call"
-       select BUILD_BIN2C
-       select CRYPTO
-       select CRYPTO_SHA256
        ---help---
          kexec is a system call that implements the ability to shutdown your
          current kernel, and to start another kernel.  It is like a reboot
@@ -1602,9 +1599,22 @@ config KEXEC
          interface is strongly in flux, so no good recommendation can be
          made.
 
+config KEXEC_FILE
+       bool "kexec file based system call"
+       select BUILD_BIN2C
+       depends on KEXEC
+       depends on X86_64
+       depends on CRYPTO=y
+       depends on CRYPTO_SHA256=y
+       ---help---
+         This is new version of kexec system call. This system call is
+         file based and takes file descriptors as system call argument
+         for kernel and initramfs as opposed to list of segments as
+         accepted by previous system call.
+
 config KEXEC_VERIFY_SIG
        bool "Verify kernel signature during kexec_file_load() syscall"
-       depends on KEXEC
+       depends on KEXEC_FILE
        ---help---
          This option makes kernel signature verification mandatory for
          kexec_file_load() syscall. If kernel is signature can not be
index c1aa368878431fe0b551cb4704b6587fd8826145..60087ca37679ccfad7c0417b8e3b32852524ba7c 100644 (file)
@@ -184,11 +184,8 @@ archheaders:
        $(Q)$(MAKE) $(build)=arch/x86/syscalls all
 
 archprepare:
-ifeq ($(CONFIG_KEXEC),y)
-# Build only for 64bit. No loaders for 32bit yet.
- ifeq ($(CONFIG_X86_64),y)
+ifeq ($(CONFIG_KEXEC_FILE),y)
        $(Q)$(MAKE) $(build)=arch/x86/purgatory arch/x86/purgatory/kexec-purgatory.c
- endif
 endif
 
 ###
@@ -254,6 +251,7 @@ archclean:
        $(Q)rm -rf $(objtree)/arch/x86_64
        $(Q)$(MAKE) $(clean)=$(boot)
        $(Q)$(MAKE) $(clean)=arch/x86/tools
+       $(Q)$(MAKE) $(clean)=arch/x86/purgatory
 
 PHONY += kvmconfig
 kvmconfig:
index 0aeed5ca356ec04bdbc4705fb6bbf5010cb65354..478c490f36547930e7101c4ad051292810fb04db 100644 (file)
@@ -227,6 +227,8 @@ static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned
 
 extern void io_apic_eoi(unsigned int apic, unsigned int vector);
 
+extern bool mp_should_keep_irq(struct device *dev);
+
 #else  /* !CONFIG_X86_IO_APIC */
 
 #define io_apic_assign_pci_irqs 0
index 572460175ba509d9317e408e96975cf10780eef7..7c492ed9087b24510a150dad80ededaaa9873b85 100644 (file)
@@ -95,7 +95,7 @@ static inline gfn_t gfn_to_index(gfn_t gfn, gfn_t base_gfn, int level)
 #define KVM_REFILL_PAGES 25
 #define KVM_MAX_CPUID_ENTRIES 80
 #define KVM_NR_FIXED_MTRR_REGION 88
-#define KVM_NR_VAR_MTRR 10
+#define KVM_NR_VAR_MTRR 8
 
 #define ASYNC_PF_PER_VCPU 64
 
index 0ec0560126180a152372ac3fc908752ea6e9ce87..aa97a070f09fbb6d31876b005a1dc86444897c10 100644 (file)
@@ -131,8 +131,13 @@ static inline int pte_exec(pte_t pte)
 
 static inline int pte_special(pte_t pte)
 {
-       return (pte_flags(pte) & (_PAGE_PRESENT|_PAGE_SPECIAL)) ==
-                                (_PAGE_PRESENT|_PAGE_SPECIAL);
+       /*
+        * See CONFIG_NUMA_BALANCING pte_numa in include/asm-generic/pgtable.h.
+        * On x86 we have _PAGE_BIT_NUMA == _PAGE_BIT_GLOBAL+1 ==
+        * __PAGE_BIT_SOFTW1 == _PAGE_BIT_SPECIAL.
+        */
+       return (pte_flags(pte) & _PAGE_SPECIAL) &&
+               (pte_flags(pte) & (_PAGE_PRESENT|_PAGE_PROTNONE));
 }
 
 static inline unsigned long pte_pfn(pte_t pte)
index eac9e92fe181e5c5b95ae164ddaeae119024997a..e21331ce368fc60a4ae7fd727448a4ca30d7bdf2 100644 (file)
 
 #define MSR_CORE_C1_RES                        0x00000660
 
+#define MSR_CC6_DEMOTION_POLICY_CONFIG 0x00000668
+#define MSR_MC6_DEMOTION_POLICY_CONFIG 0x00000669
+
 #define MSR_AMD64_MC0_MASK             0xc0010044
 
 #define MSR_IA32_MCx_CTL(x)            (MSR_IA32_MC0_CTL + 4*(x))
index b5ea75c4a4b411d14ae2bf810eb7d40bde9f8716..ada2e2d6be3e01335734016a2aae5dc677ab69af 100644 (file)
@@ -71,6 +71,7 @@ obj-$(CONFIG_FTRACE_SYSCALLS) += ftrace.o
 obj-$(CONFIG_X86_TSC)          += trace_clock.o
 obj-$(CONFIG_KEXEC)            += machine_kexec_$(BITS).o
 obj-$(CONFIG_KEXEC)            += relocate_kernel_$(BITS).o crash.o
+obj-$(CONFIG_KEXEC_FILE)       += kexec-bzimage64.o
 obj-$(CONFIG_CRASH_DUMP)       += crash_dump_$(BITS).o
 obj-y                          += kprobes/
 obj-$(CONFIG_MODULES)          += module.o
@@ -118,5 +119,4 @@ ifeq ($(CONFIG_X86_64),y)
 
        obj-$(CONFIG_PCI_MMCONFIG)      += mmconf-fam10h_64.o
        obj-y                           += vsmp_64.o
-       obj-$(CONFIG_KEXEC)             += kexec-bzimage64.o
 endif
index 29290f554e7963fc104cd385921692a6bbc41470..337ce5a9b15c86bb7e9ea7747749fed1aee0d2d7 100644 (file)
@@ -1070,6 +1070,11 @@ static int mp_map_pin_to_irq(u32 gsi, int idx, int ioapic, int pin,
        }
 
        if (flags & IOAPIC_MAP_ALLOC) {
+               /* special handling for legacy IRQs */
+               if (irq < nr_legacy_irqs() && info->count == 1 &&
+                   mp_irqdomain_map(domain, irq, pin) != 0)
+                       irq = -1;
+
                if (irq > 0)
                        info->count++;
                else if (info->count == 0)
@@ -3896,7 +3901,15 @@ int mp_irqdomain_map(struct irq_domain *domain, unsigned int virq,
                        info->polarity = 1;
                }
                info->node = NUMA_NO_NODE;
-               info->set = 1;
+
+               /*
+                * setup_IO_APIC_irqs() programs all legacy IRQs with default
+                * trigger and polarity attributes. Don't set the flag for that
+                * case so the first legacy IRQ user could reprogram the pin
+                * with real trigger and polarity attributes.
+                */
+               if (virq >= nr_legacy_irqs() || info->count)
+                       info->set = 1;
        }
        set_io_apic_irq_attr(&attr, ioapic, hwirq, info->trigger,
                             info->polarity);
@@ -3946,6 +3959,18 @@ int mp_set_gsi_attr(u32 gsi, int trigger, int polarity, int node)
        return ret;
 }
 
+bool mp_should_keep_irq(struct device *dev)
+{
+       if (dev->power.is_prepared)
+               return true;
+#ifdef CONFIG_PM_RUNTIME
+       if (dev->power.runtime_status == RPM_SUSPENDING)
+               return true;
+#endif
+
+       return false;
+}
+
 /* Enable IOAPIC early just for system timer */
 void __init pre_init_apic_IRQ0(void)
 {
index 0553a34fa0df9eacf9336ee9076b28802531240b..a618fcd2c07d3d54062a8558a7f9941b16859203 100644 (file)
@@ -182,8 +182,7 @@ void native_machine_crash_shutdown(struct pt_regs *regs)
        crash_save_cpu(regs, safe_smp_processor_id());
 }
 
-#ifdef CONFIG_X86_64
-
+#ifdef CONFIG_KEXEC_FILE
 static int get_nr_ram_ranges_callback(unsigned long start_pfn,
                                unsigned long nr_pfn, void *arg)
 {
@@ -696,5 +695,4 @@ int crash_load_segments(struct kimage *image)
 
        return ret;
 }
-
-#endif /* CONFIG_X86_64 */
+#endif /* CONFIG_KEXEC_FILE */
index 47c410d99f5daaae8a7d4f3f00093a6496e099ec..4b0e1dfa222627cd5a36fb7b8f51234508822536 100644 (file)
@@ -683,7 +683,7 @@ END(syscall_badsys)
 sysenter_badsys:
        movl $-ENOSYS,%eax
        jmp sysenter_after_call
-END(syscall_badsys)
+END(sysenter_badsys)
        CFI_ENDPROC
 
 .macro FIXUP_ESPFIX_STACK
index 1e6cff5814fa62ea0aefdc9d87fc1dec532d16e6..44f1ed42fdf2136c0b2654256745d20edca1a28d 100644 (file)
@@ -203,7 +203,7 @@ void __init native_init_IRQ(void)
                set_intr_gate(i, interrupt[i - FIRST_EXTERNAL_VECTOR]);
        }
 
-       if (!acpi_ioapic && !of_ioapic)
+       if (!acpi_ioapic && !of_ioapic && nr_legacy_irqs())
                setup_irq(2, &irq2);
 
 #ifdef CONFIG_X86_32
index 8b04018e5d1f0732f1d1c3cf3ad092352d1409d6..485981059a40e703e7be8debd49a14e45dde0e54 100644 (file)
 #include <asm/debugreg.h>
 #include <asm/kexec-bzimage64.h>
 
+#ifdef CONFIG_KEXEC_FILE
 static struct kexec_file_ops *kexec_file_loaders[] = {
                &kexec_bzImage64_ops,
 };
+#endif
 
 static void free_transition_pgtable(struct kimage *image)
 {
@@ -178,6 +180,7 @@ static void load_segments(void)
                );
 }
 
+#ifdef CONFIG_KEXEC_FILE
 /* Update purgatory as needed after various image segments have been prepared */
 static int arch_update_purgatory(struct kimage *image)
 {
@@ -209,6 +212,12 @@ static int arch_update_purgatory(struct kimage *image)
 
        return ret;
 }
+#else /* !CONFIG_KEXEC_FILE */
+static inline int arch_update_purgatory(struct kimage *image)
+{
+       return 0;
+}
+#endif /* CONFIG_KEXEC_FILE */
 
 int machine_kexec_prepare(struct kimage *image)
 {
@@ -329,6 +338,7 @@ void arch_crash_save_vmcoreinfo(void)
 
 /* arch-dependent functionality related to kexec file-based syscall */
 
+#ifdef CONFIG_KEXEC_FILE
 int arch_kexec_kernel_image_probe(struct kimage *image, void *buf,
                                  unsigned long buf_len)
 {
@@ -522,3 +532,4 @@ overflow:
               (int)ELF64_R_TYPE(rel[i].r_info), value);
        return -ENOEXEC;
 }
+#endif /* CONFIG_KEXEC_FILE */
index bf7ef5ce29dff7f89d8e93fb8bee4119f445379b..0fa29609b2c42236c7cd5bd913533cf18b895cc3 100644 (file)
@@ -68,6 +68,8 @@ static struct irqaction irq0  = {
 
 void __init setup_default_timer_irq(void)
 {
+       if (!nr_legacy_irqs())
+               return;
        setup_irq(0, &irq0);
 }
 
index 56657b0bb3bb14f14b76fdcd99a746598ce5e8b4..03954f7900f522a496d8249174ec63cc760aa140 100644 (file)
@@ -1491,9 +1491,6 @@ static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt,
                        goto exception;
                break;
        case VCPU_SREG_CS:
-               if (in_task_switch && rpl != dpl)
-                       goto exception;
-
                if (!(seg_desc.type & 8))
                        goto exception;
 
@@ -4394,8 +4391,11 @@ done_prefixes:
 
        ctxt->execute = opcode.u.execute;
 
+       if (unlikely(ctxt->ud) && likely(!(ctxt->d & EmulateOnUD)))
+               return EMULATION_FAILED;
+
        if (unlikely(ctxt->d &
-                    (NotImpl|EmulateOnUD|Stack|Op3264|Sse|Mmx|Intercept|CheckPerm))) {
+                    (NotImpl|Stack|Op3264|Sse|Mmx|Intercept|CheckPerm))) {
                /*
                 * These are copied unconditionally here, and checked unconditionally
                 * in x86_emulate_insn.
@@ -4406,9 +4406,6 @@ done_prefixes:
                if (ctxt->d & NotImpl)
                        return EMULATION_FAILED;
 
-               if (!(ctxt->d & EmulateOnUD) && ctxt->ud)
-                       return EMULATION_FAILED;
-
                if (mode == X86EMUL_MODE_PROT64 && (ctxt->d & Stack))
                        ctxt->op_bytes = 8;
 
index 1fe33987de027f73c2997960198978a557bb1027..ee61c36d64f84dd944873ec0acf80b4f8ad06da7 100644 (file)
@@ -49,7 +49,13 @@ void leave_mm(int cpu)
        if (cpumask_test_cpu(cpu, mm_cpumask(active_mm))) {
                cpumask_clear_cpu(cpu, mm_cpumask(active_mm));
                load_cr3(swapper_pg_dir);
-               trace_tlb_flush(TLB_FLUSH_ON_TASK_SWITCH, TLB_FLUSH_ALL);
+               /*
+                * This gets called in the idle path where RCU
+                * functions differently.  Tracing normally
+                * uses RCU, so we have to call the tracepoint
+                * specially here.
+                */
+               trace_tlb_flush_rcuidle(TLB_FLUSH_ON_TASK_SWITCH, TLB_FLUSH_ALL);
        }
 }
 EXPORT_SYMBOL_GPL(leave_mm);
@@ -174,7 +180,7 @@ void flush_tlb_current_task(void)
  *
  * This is in units of pages.
  */
-unsigned long tlb_single_page_flush_ceiling = 33;
+static unsigned long tlb_single_page_flush_ceiling __read_mostly = 33;
 
 void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start,
                                unsigned long end, unsigned long vmflag)
index 5c8cb8043c5a2b19df3e524d9d35ee3ec1949cd5..d56cd1f515bdb8037e67e0cbd45d1bd7b5c0db7f 100644 (file)
@@ -8,12 +8,10 @@
  * as published by the Free Software Foundation; version 2
  * of the License.
  */
-#include <linux/moduleloader.h>
-#include <asm/cacheflush.h>
 #include <linux/netdevice.h>
 #include <linux/filter.h>
 #include <linux/if_vlan.h>
-#include <linux/random.h>
+#include <asm/cacheflush.h>
 
 int bpf_jit_enable __read_mostly;
 
@@ -109,39 +107,6 @@ static inline void bpf_flush_icache(void *start, void *end)
 #define CHOOSE_LOAD_FUNC(K, func) \
        ((int)K < 0 ? ((int)K >= SKF_LL_OFF ? func##_negative_offset : func) : func##_positive_offset)
 
-struct bpf_binary_header {
-       unsigned int    pages;
-       /* Note : for security reasons, bpf code will follow a randomly
-        * sized amount of int3 instructions
-        */
-       u8              image[];
-};
-
-static struct bpf_binary_header *bpf_alloc_binary(unsigned int proglen,
-                                                 u8 **image_ptr)
-{
-       unsigned int sz, hole;
-       struct bpf_binary_header *header;
-
-       /* Most of BPF filters are really small,
-        * but if some of them fill a page, allow at least
-        * 128 extra bytes to insert a random section of int3
-        */
-       sz = round_up(proglen + sizeof(*header) + 128, PAGE_SIZE);
-       header = module_alloc(sz);
-       if (!header)
-               return NULL;
-
-       memset(header, 0xcc, sz); /* fill whole space with int3 instructions */
-
-       header->pages = sz / PAGE_SIZE;
-       hole = min(sz - (proglen + sizeof(*header)), PAGE_SIZE - sizeof(*header));
-
-       /* insert a random number of int3 instructions before BPF code */
-       *image_ptr = &header->image[prandom_u32() % hole];
-       return header;
-}
-
 /* pick a register outside of BPF range for JIT internal work */
 #define AUX_REG (MAX_BPF_REG + 1)
 
@@ -206,6 +171,12 @@ static inline u8 add_2reg(u8 byte, u32 dst_reg, u32 src_reg)
        return byte + reg2hex[dst_reg] + (reg2hex[src_reg] << 3);
 }
 
+static void jit_fill_hole(void *area, unsigned int size)
+{
+       /* fill whole space with int3 instructions */
+       memset(area, 0xcc, size);
+}
+
 struct jit_context {
        unsigned int cleanup_addr; /* epilogue code offset */
        bool seen_ld_abs;
@@ -393,6 +364,23 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
                        EMIT1_off32(add_1reg(0xB8, dst_reg), imm32);
                        break;
 
+               case BPF_LD | BPF_IMM | BPF_DW:
+                       if (insn[1].code != 0 || insn[1].src_reg != 0 ||
+                           insn[1].dst_reg != 0 || insn[1].off != 0) {
+                               /* verifier must catch invalid insns */
+                               pr_err("invalid BPF_LD_IMM64 insn\n");
+                               return -EINVAL;
+                       }
+
+                       /* movabsq %rax, imm64 */
+                       EMIT2(add_1mod(0x48, dst_reg), add_1reg(0xB8, dst_reg));
+                       EMIT(insn[0].imm, 4);
+                       EMIT(insn[1].imm, 4);
+
+                       insn++;
+                       i++;
+                       break;
+
                        /* dst %= src, dst /= src, dst %= imm32, dst /= imm32 */
                case BPF_ALU | BPF_MOD | BPF_X:
                case BPF_ALU | BPF_DIV | BPF_X:
@@ -515,6 +503,48 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
                        EMIT3(0xC1, add_1reg(b3, dst_reg), imm32);
                        break;
 
+               case BPF_ALU | BPF_LSH | BPF_X:
+               case BPF_ALU | BPF_RSH | BPF_X:
+               case BPF_ALU | BPF_ARSH | BPF_X:
+               case BPF_ALU64 | BPF_LSH | BPF_X:
+               case BPF_ALU64 | BPF_RSH | BPF_X:
+               case BPF_ALU64 | BPF_ARSH | BPF_X:
+
+                       /* check for bad case when dst_reg == rcx */
+                       if (dst_reg == BPF_REG_4) {
+                               /* mov r11, dst_reg */
+                               EMIT_mov(AUX_REG, dst_reg);
+                               dst_reg = AUX_REG;
+                       }
+
+                       if (src_reg != BPF_REG_4) { /* common case */
+                               EMIT1(0x51); /* push rcx */
+
+                               /* mov rcx, src_reg */
+                               EMIT_mov(BPF_REG_4, src_reg);
+                       }
+
+                       /* shl %rax, %cl | shr %rax, %cl | sar %rax, %cl */
+                       if (BPF_CLASS(insn->code) == BPF_ALU64)
+                               EMIT1(add_1mod(0x48, dst_reg));
+                       else if (is_ereg(dst_reg))
+                               EMIT1(add_1mod(0x40, dst_reg));
+
+                       switch (BPF_OP(insn->code)) {
+                       case BPF_LSH: b3 = 0xE0; break;
+                       case BPF_RSH: b3 = 0xE8; break;
+                       case BPF_ARSH: b3 = 0xF8; break;
+                       }
+                       EMIT2(0xD3, add_1reg(b3, dst_reg));
+
+                       if (src_reg != BPF_REG_4)
+                               EMIT1(0x59); /* pop rcx */
+
+                       if (insn->dst_reg == BPF_REG_4)
+                               /* mov dst_reg, r11 */
+                               EMIT_mov(insn->dst_reg, AUX_REG);
+                       break;
+
                case BPF_ALU | BPF_END | BPF_FROM_BE:
                        switch (imm32) {
                        case 16:
@@ -900,7 +930,7 @@ void bpf_int_jit_compile(struct bpf_prog *prog)
                if (proglen <= 0) {
                        image = NULL;
                        if (header)
-                               module_free(NULL, header);
+                               bpf_jit_binary_free(header);
                        goto out;
                }
                if (image) {
@@ -910,7 +940,8 @@ void bpf_int_jit_compile(struct bpf_prog *prog)
                        break;
                }
                if (proglen == oldproglen) {
-                       header = bpf_alloc_binary(proglen, &image);
+                       header = bpf_jit_binary_alloc(proglen, &image,
+                                                     1, jit_fill_hole);
                        if (!header)
                                goto out;
                }
@@ -924,29 +955,23 @@ void bpf_int_jit_compile(struct bpf_prog *prog)
                bpf_flush_icache(header, image + proglen);
                set_memory_ro((unsigned long)header, header->pages);
                prog->bpf_func = (void *)image;
-               prog->jited = 1;
+               prog->jited = true;
        }
 out:
        kfree(addrs);
 }
 
-static void bpf_jit_free_deferred(struct work_struct *work)
+void bpf_jit_free(struct bpf_prog *fp)
 {
-       struct bpf_prog *fp = container_of(work, struct bpf_prog, work);
        unsigned long addr = (unsigned long)fp->bpf_func & PAGE_MASK;
        struct bpf_binary_header *header = (void *)addr;
 
+       if (!fp->jited)
+               goto free_filter;
+
        set_memory_rw(addr, header->pages);
-       module_free(NULL, header);
-       kfree(fp);
-}
+       bpf_jit_binary_free(header);
 
-void bpf_jit_free(struct bpf_prog *fp)
-{
-       if (fp->jited) {
-               INIT_WORK(&fp->work, bpf_jit_free_deferred);
-               schedule_work(&fp->work);
-       } else {
-               kfree(fp);
-       }
+free_filter:
+       bpf_prog_unlock_free(fp);
 }
index 3865116c51fbf583a923d4131882c653b5fc3c24..b9958c364075e949620001cc9d8f02a2715d0128 100644 (file)
@@ -229,7 +229,7 @@ static int intel_mid_pci_irq_enable(struct pci_dev *dev)
 
 static void intel_mid_pci_irq_disable(struct pci_dev *dev)
 {
-       if (!dev->dev.power.is_prepared && dev->irq > 0)
+       if (!mp_should_keep_irq(&dev->dev) && dev->irq > 0)
                mp_unmap_irq(dev->irq);
 }
 
index bc1a2c341891034d04c86b834c5d132e7f954e33..eb500c2592ad8ab4ced728f676d9102411fa3782 100644 (file)
@@ -1256,7 +1256,7 @@ static int pirq_enable_irq(struct pci_dev *dev)
 
 static void pirq_disable_irq(struct pci_dev *dev)
 {
-       if (io_apic_assign_pci_irqs && !dev->dev.power.is_prepared &&
+       if (io_apic_assign_pci_irqs && !mp_should_keep_irq(&dev->dev) &&
            dev->irq) {
                mp_unmap_irq(dev->irq);
                dev->irq = 0;
index 7fde9ee438a43b0e1f55b4c2db3fb90b83c3f1ce..899dd24542568de85e815e4b9f206d66286bca8c 100644 (file)
@@ -11,6 +11,7 @@ targets += purgatory.ro
 # sure how to relocate those. Like kexec-tools, use custom flags.
 
 KBUILD_CFLAGS := -fno-strict-aliasing -Wall -Wstrict-prototypes -fno-zero-initialized-in-bss -fno-builtin -ffreestanding -c -MD -Os -mcmodel=large
+KBUILD_CFLAGS += -m$(BITS)
 
 $(obj)/purgatory.ro: $(PURGATORY_OBJS) FORCE
                $(call if_changed,ld)
@@ -24,7 +25,4 @@ $(obj)/kexec-purgatory.c: $(obj)/purgatory.ro FORCE
        $(call if_changed,bin2c)
 
 
-# No loaders for 32bits yet.
-ifeq ($(CONFIG_X86_64),y)
- obj-$(CONFIG_KEXEC)           += kexec-purgatory.o
-endif
+obj-$(CONFIG_KEXEC_FILE)       += kexec-purgatory.o
index 3a617af60d465196bb894cebdc4042ccd4e4a92f..49c6c3d9444916e0dc727d51c96349e92c424d6a 100644 (file)
@@ -4,24 +4,23 @@ config ZONE_DMA
 config XTENSA
        def_bool y
        select ARCH_WANT_FRAME_POINTERS
-       select HAVE_IDE
-       select GENERIC_ATOMIC64
-       select GENERIC_CLOCKEVENTS
-       select VIRT_TO_BUS
-       select GENERIC_IRQ_SHOW
-       select GENERIC_SCHED_CLOCK
-       select MODULES_USE_ELF_RELA
-       select GENERIC_PCI_IOMAP
        select ARCH_WANT_IPC_PARSE_VERSION
        select ARCH_WANT_OPTIONAL_GPIOLIB
        select BUILDTIME_EXTABLE_SORT
        select CLONE_BACKWARDS
-       select IRQ_DOMAIN
-       select HAVE_OPROFILE
+       select COMMON_CLK
+       select GENERIC_ATOMIC64
+       select GENERIC_CLOCKEVENTS
+       select GENERIC_IRQ_SHOW
+       select GENERIC_PCI_IOMAP
+       select GENERIC_SCHED_CLOCK
        select HAVE_FUNCTION_TRACER
        select HAVE_IRQ_TIME_ACCOUNTING
+       select HAVE_OPROFILE
        select HAVE_PERF_EVENTS
-       select COMMON_CLK
+       select IRQ_DOMAIN
+       select MODULES_USE_ELF_RELA
+       select VIRT_TO_BUS
        help
          Xtensa processors are 32-bit RISC machines designed by Tensilica
          primarily for embedded systems.  These processors are both
@@ -62,7 +61,9 @@ config TRACE_IRQFLAGS_SUPPORT
        def_bool y
 
 config MMU
-       def_bool n
+       bool
+       default n if !XTENSA_VARIANT_CUSTOM
+       default XTENSA_VARIANT_MMU if XTENSA_VARIANT_CUSTOM
 
 config VARIANT_IRQ_SWITCH
        def_bool n
@@ -102,8 +103,40 @@ config XTENSA_VARIANT_S6000
        select VARIANT_IRQ_SWITCH
        select ARCH_REQUIRE_GPIOLIB
        select XTENSA_CALIBRATE_CCOUNT
+
+config XTENSA_VARIANT_CUSTOM
+       bool "Custom Xtensa processor configuration"
+       select MAY_HAVE_SMP
+       select HAVE_XTENSA_GPIO32
+       help
+         Select this variant to use a custom Xtensa processor configuration.
+         You will be prompted for a processor variant CORENAME.
 endchoice
 
+config XTENSA_VARIANT_CUSTOM_NAME
+       string "Xtensa Processor Custom Core Variant Name"
+       depends on XTENSA_VARIANT_CUSTOM
+       help
+         Provide the name of a custom Xtensa processor variant.
+         This CORENAME selects arch/xtensa/variant/CORENAME.
+         Dont forget you have to select MMU if you have one.
+
+config XTENSA_VARIANT_NAME
+       string
+       default "dc232b"                        if XTENSA_VARIANT_DC232B
+       default "dc233c"                        if XTENSA_VARIANT_DC233C
+       default "fsf"                           if XTENSA_VARIANT_FSF
+       default "s6000"                         if XTENSA_VARIANT_S6000
+       default XTENSA_VARIANT_CUSTOM_NAME      if XTENSA_VARIANT_CUSTOM
+
+config XTENSA_VARIANT_MMU
+       bool "Core variant has a Full MMU (TLB, Pages, Protection, etc)"
+       depends on XTENSA_VARIANT_CUSTOM
+       default y
+       help
+         Build a Conventional Kernel with full MMU support,
+         ie: it supports a TLB with auto-loading, page protection.
+
 config XTENSA_UNALIGNED_USER
        bool "Unaligned memory access in use space"
        help
@@ -156,13 +189,9 @@ config HOTPLUG_CPU
 
          Say N if you want to disable CPU hotplug.
 
-config MATH_EMULATION
-       bool "Math emulation"
-       help
-       Can we use information of configuration file?
-
 config INITIALIZE_XTENSA_MMU_INSIDE_VMLINUX
        bool "Initialize Xtensa MMU inside the Linux kernel code"
+       depends on MMU
        default y
        help
          Earlier version initialized the MMU in the exception vector
@@ -192,6 +221,7 @@ config INITIALIZE_XTENSA_MMU_INSIDE_VMLINUX
 
 config HIGHMEM
        bool "High Memory Support"
+       depends on MMU
        help
          Linux can use the full amount of RAM in the system by
          default. However, the default MMUv2 setup only maps the
@@ -208,6 +238,32 @@ config HIGHMEM
 
          If unsure, say Y.
 
+config FAST_SYSCALL_XTENSA
+       bool "Enable fast atomic syscalls"
+       default n
+       help
+         fast_syscall_xtensa is a syscall that can make atomic operations
+         on UP kernel when processor has no s32c1i support.
+
+         This syscall is deprecated. It may have issues when called with
+         invalid arguments. It is provided only for backwards compatibility.
+         Only enable it if your userspace software requires it.
+
+         If unsure, say N.
+
+config FAST_SYSCALL_SPILL_REGISTERS
+       bool "Enable spill registers syscall"
+       default n
+       help
+         fast_syscall_spill_registers is a syscall that spills all active
+         register windows of a calling userspace task onto its stack.
+
+         This syscall is deprecated. It may have issues when called with
+         invalid arguments. It is provided only for backwards compatibility.
+         Only enable it if your userspace software requires it.
+
+         If unsure, say N.
+
 endmenu
 
 config XTENSA_CALIBRATE_CCOUNT
@@ -250,12 +306,14 @@ config XTENSA_PLATFORM_ISS
 
 config XTENSA_PLATFORM_XT2000
        bool "XT2000"
+       select HAVE_IDE
        help
          XT2000 is the name of Tensilica's feature-rich emulation platform.
          This hardware is capable of running a full Linux distribution.
 
 config XTENSA_PLATFORM_S6105
        bool "S6105"
+       select HAVE_IDE
        select SERIAL_CONSOLE
        select NO_IOPORT_MAP
 
index 81250ece3062ae914628d8b49f777ac7de580263..472533064b465d126ab95434a6b285050fa4890f 100644 (file)
@@ -4,6 +4,7 @@
 # for more details.
 #
 # Copyright (C) 2001 - 2005  Tensilica Inc.
+# Copyright (C) 2014 Cadence Design Systems Inc.
 #
 # This file is included by the global makefile so that you can add your own
 # architecture-specific flags and dependencies. Remember to do have actions
 # Core configuration.
 # (Use VAR=<xtensa_config> to use another default compiler.)
 
-variant-$(CONFIG_XTENSA_VARIANT_FSF)           := fsf
-variant-$(CONFIG_XTENSA_VARIANT_DC232B)                := dc232b
-variant-$(CONFIG_XTENSA_VARIANT_DC233C)                := dc233c
-variant-$(CONFIG_XTENSA_VARIANT_S6000)         := s6000
-variant-$(CONFIG_XTENSA_VARIANT_LINUX_CUSTOM)  := custom
+variant-y := $(patsubst "%",%,$(CONFIG_XTENSA_VARIANT_NAME))
 
 VARIANT = $(variant-y)
 export VARIANT
index 742a347be67a3ef7651615435f7d41711f8c139e..c4d17a34ab86ca3d61ca85f398cf0fd80b753f41 100644 (file)
@@ -4,8 +4,11 @@
 
 / {
        compatible = "cdns,xtensa-kc705";
+       chosen {
+               bootargs = "earlycon=uart8250,mmio32,0xfd050020,115200n8 console=ttyS0,115200n8 ip=dhcp root=/dev/nfs rw debug memmap=0x38000000";
+       };
        memory@0 {
                device_type = "memory";
-               reg = <0x00000000 0x08000000>;
+               reg = <0x00000000 0x38000000>;
        };
 };
index f6000fe05119a1a9ad5f79cff94c4516b106809d..721df1214bc3bff9026f5f593a7453b2a8341a68 100644 (file)
@@ -66,7 +66,6 @@ CONFIG_XTENSA_ARCH_LINUX_BE=y
 CONFIG_MMU=y
 # CONFIG_XTENSA_UNALIGNED_USER is not set
 # CONFIG_PREEMPT is not set
-# CONFIG_MATH_EMULATION is not set
 # CONFIG_HIGHMEM is not set
 
 #
index 1493c68352d11454a50a7fdfb5f11f49ab54de88..b966baf82cae8af3f52e6500414af80326937b6d 100644 (file)
@@ -146,7 +146,6 @@ CONFIG_XTENSA_VARIANT_FSF=y
 # CONFIG_XTENSA_VARIANT_S6000 is not set
 # CONFIG_XTENSA_UNALIGNED_USER is not set
 # CONFIG_PREEMPT is not set
-# CONFIG_MATH_EMULATION is not set
 CONFIG_XTENSA_CALIBRATE_CCOUNT=y
 CONFIG_SERIAL_CONSOLE=y
 CONFIG_XTENSA_ISS_NETWORK=y
@@ -308,7 +307,7 @@ CONFIG_MISC_DEVICES=y
 # EEPROM support
 #
 # CONFIG_EEPROM_93CX6 is not set
-CONFIG_HAVE_IDE=y
+# CONFIG_HAVE_IDE is not set
 # CONFIG_IDE is not set
 
 #
index 12a492ab6d17f9fbf74dedd1a9723a269ee7cbef..9471265b8ca69e1a4bce9dcc531dae2d8d03e271 100644 (file)
@@ -109,7 +109,6 @@ CONFIG_VARIANT_IRQ_SWITCH=y
 CONFIG_XTENSA_VARIANT_S6000=y
 # CONFIG_XTENSA_UNALIGNED_USER is not set
 CONFIG_PREEMPT=y
-# CONFIG_MATH_EMULATION is not set
 # CONFIG_HIGHMEM is not set
 CONFIG_XTENSA_CALIBRATE_CCOUNT=y
 CONFIG_SERIAL_CONSOLE=y
index 555a98a1845363588ced5fd3ec26a2269846e3d8..e72aaca7a77fc112161cc22133b6c1305cc5c3ae 100644 (file)
@@ -37,6 +37,7 @@
  * specials for cache aliasing:
  *
  * __flush_invalidate_dcache_page_alias(vaddr,paddr)
+ * __invalidate_dcache_page_alias(vaddr,paddr)
  * __invalidate_icache_page_alias(vaddr,paddr)
  */
 
@@ -62,6 +63,7 @@ extern void __flush_invalidate_dcache_range(unsigned long, unsigned long);
 
 #if defined(CONFIG_MMU) && (DCACHE_WAY_SIZE > PAGE_SIZE)
 extern void __flush_invalidate_dcache_page_alias(unsigned long, unsigned long);
+extern void __invalidate_dcache_page_alias(unsigned long, unsigned long);
 #else
 static inline void __flush_invalidate_dcache_page_alias(unsigned long virt,
                                                        unsigned long phys) { }
index 9f6c33d0428a73d6b59f601992aede5a956dc3da..62b507deea9da136cc26cf32388a5a3358efa251 100644 (file)
@@ -23,8 +23,8 @@
  * Here we define all the compile-time 'special' virtual
  * addresses. The point is to have a constant address at
  * compile time, but to set the physical address only
- * in the boot process. We allocate these special  addresses
- * from the end of the consistent memory region backwards.
+ * in the boot process. We allocate these special addresses
+ * from the start of the consistent memory region upwards.
  * Also this lets us do fail-safe vmalloc(), we
  * can guarantee that these special addresses and
  * vmalloc()-ed addresses never overlap.
@@ -38,7 +38,8 @@ enum fixed_addresses {
 #ifdef CONFIG_HIGHMEM
        /* reserved pte's for temporary kernel mappings */
        FIX_KMAP_BEGIN,
-       FIX_KMAP_END = FIX_KMAP_BEGIN + (KM_TYPE_NR * NR_CPUS) - 1,
+       FIX_KMAP_END = FIX_KMAP_BEGIN +
+               (KM_TYPE_NR * NR_CPUS * DCACHE_N_COLORS) - 1,
 #endif
        __end_of_fixed_addresses
 };
@@ -47,7 +48,28 @@ enum fixed_addresses {
 #define FIXADDR_SIZE   (__end_of_fixed_addresses << PAGE_SHIFT)
 #define FIXADDR_START  ((FIXADDR_TOP - FIXADDR_SIZE) & PMD_MASK)
 
-#include <asm-generic/fixmap.h>
+#define __fix_to_virt(x)       (FIXADDR_START + ((x) << PAGE_SHIFT))
+#define __virt_to_fix(x)       (((x) - FIXADDR_START) >> PAGE_SHIFT)
+
+#ifndef __ASSEMBLY__
+/*
+ * 'index to address' translation. If anyone tries to use the idx
+ * directly without translation, we catch the bug with a NULL-deference
+ * kernel oops. Illegal ranges of incoming indices are caught too.
+ */
+static __always_inline unsigned long fix_to_virt(const unsigned int idx)
+{
+       BUILD_BUG_ON(idx >= __end_of_fixed_addresses);
+       return __fix_to_virt(idx);
+}
+
+static inline unsigned long virt_to_fix(const unsigned long vaddr)
+{
+       BUG_ON(vaddr >= FIXADDR_TOP || vaddr < FIXADDR_START);
+       return __virt_to_fix(vaddr);
+}
+
+#endif
 
 #define kmap_get_fixmap_pte(vaddr) \
        pte_offset_kernel( \
index 2653ef5d55f1c9ed92d35d50f91136732334ec1b..2c7901edffaf3a6b38714386294c633a8aa7d8c3 100644 (file)
 #ifndef _XTENSA_HIGHMEM_H
 #define _XTENSA_HIGHMEM_H
 
+#include <linux/wait.h>
 #include <asm/cacheflush.h>
 #include <asm/fixmap.h>
 #include <asm/kmap_types.h>
 #include <asm/pgtable.h>
 
-#define PKMAP_BASE             (FIXADDR_START - PMD_SIZE)
-#define LAST_PKMAP             PTRS_PER_PTE
+#define PKMAP_BASE             ((FIXADDR_START - \
+                                 (LAST_PKMAP + 1) * PAGE_SIZE) & PMD_MASK)
+#define LAST_PKMAP             (PTRS_PER_PTE * DCACHE_N_COLORS)
 #define LAST_PKMAP_MASK                (LAST_PKMAP - 1)
 #define PKMAP_NR(virt)         (((virt) - PKMAP_BASE) >> PAGE_SHIFT)
 #define PKMAP_ADDR(nr)         (PKMAP_BASE + ((nr) << PAGE_SHIFT))
 
 #define kmap_prot              PAGE_KERNEL
 
+#if DCACHE_WAY_SIZE > PAGE_SIZE
+#define get_pkmap_color get_pkmap_color
+static inline int get_pkmap_color(struct page *page)
+{
+       return DCACHE_ALIAS(page_to_phys(page));
+}
+
+extern unsigned int last_pkmap_nr_arr[];
+
+static inline unsigned int get_next_pkmap_nr(unsigned int color)
+{
+       last_pkmap_nr_arr[color] =
+               (last_pkmap_nr_arr[color] + DCACHE_N_COLORS) & LAST_PKMAP_MASK;
+       return last_pkmap_nr_arr[color] + color;
+}
+
+static inline int no_more_pkmaps(unsigned int pkmap_nr, unsigned int color)
+{
+       return pkmap_nr < DCACHE_N_COLORS;
+}
+
+static inline int get_pkmap_entries_count(unsigned int color)
+{
+       return LAST_PKMAP / DCACHE_N_COLORS;
+}
+
+extern wait_queue_head_t pkmap_map_wait_arr[];
+
+static inline wait_queue_head_t *get_pkmap_wait_queue_head(unsigned int color)
+{
+       return pkmap_map_wait_arr + color;
+}
+#endif
+
 extern pte_t *pkmap_page_table;
 
 void *kmap_high(struct page *page);
index 47f582333f6b799b246a39577e96bf1dced7cee3..abe24c6f8b2f06f112f9e9933306bcdd5a924d4d 100644 (file)
@@ -78,7 +78,9 @@
 # define DCACHE_ALIAS_EQ(a,b)  ((((a) ^ (b)) & DCACHE_ALIAS_MASK) == 0)
 #else
 # define DCACHE_ALIAS_ORDER    0
+# define DCACHE_ALIAS(a)       ((void)(a), 0)
 #endif
+#define DCACHE_N_COLORS                (1 << DCACHE_ALIAS_ORDER)
 
 #if ICACHE_WAY_SIZE > PAGE_SIZE
 # define ICACHE_ALIAS_ORDER    (ICACHE_WAY_SHIFT - PAGE_SHIFT)
@@ -134,6 +136,7 @@ static inline __attribute_const__ int get_order(unsigned long size)
 #endif
 
 struct page;
+struct vm_area_struct;
 extern void clear_page(void *page);
 extern void copy_page(void *to, void *from);
 
@@ -143,8 +146,15 @@ extern void copy_page(void *to, void *from);
  */
 
 #if DCACHE_WAY_SIZE > PAGE_SIZE
-extern void clear_user_page(void*, unsigned long, struct page*);
-extern void copy_user_page(void*, void*, unsigned long, struct page*);
+extern void clear_page_alias(void *vaddr, unsigned long paddr);
+extern void copy_page_alias(void *to, void *from,
+                           unsigned long to_paddr, unsigned long from_paddr);
+
+#define clear_user_highpage clear_user_highpage
+void clear_user_highpage(struct page *page, unsigned long vaddr);
+#define __HAVE_ARCH_COPY_USER_HIGHPAGE
+void copy_user_highpage(struct page *to, struct page *from,
+                       unsigned long vaddr, struct vm_area_struct *vma);
 #else
 # define clear_user_page(page, vaddr, pg)      clear_page(page)
 # define copy_user_page(to, from, vaddr, pg)   copy_page(to, from)
index 4b0ca35a93b1a731bf0ce2c1db32f9fabb890fef..b2173e5da601cbe57303f9060faacb0dde0310cf 100644 (file)
 #define VMALLOC_START          0xC0000000
 #define VMALLOC_END            0xC7FEFFFF
 #define TLBTEMP_BASE_1         0xC7FF0000
-#define TLBTEMP_BASE_2         0xC7FF8000
+#define TLBTEMP_BASE_2         (TLBTEMP_BASE_1 + DCACHE_WAY_SIZE)
+#if 2 * DCACHE_WAY_SIZE > ICACHE_WAY_SIZE
+#define TLBTEMP_SIZE           (2 * DCACHE_WAY_SIZE)
+#else
+#define TLBTEMP_SIZE           ICACHE_WAY_SIZE
+#endif
 
 /*
  * For the Xtensa architecture, the PTE layout is as follows:
index fd686dc45d1a95b5016de15341c6d3fe173837fe..c7211e7e182d56cd85e3ec923ee89f81748b26af 100644 (file)
  */
        .macro  get_fs  ad, sp
        GET_CURRENT(\ad,\sp)
+#if THREAD_CURRENT_DS > 1020
+       addi    \ad, \ad, TASK_THREAD
+       l32i    \ad, \ad, THREAD_CURRENT_DS - TASK_THREAD
+#else
        l32i    \ad, \ad, THREAD_CURRENT_DS
+#endif
        .endm
 
 /*
index b4cb1100c0fb01f6ca178ef5c3f0e4adc02b8f9a..a47909f0c34b4892848d06b9f55ebe4a37563d90 100644 (file)
 #define TCSETSW                0x5403
 #define TCSETSF                0x5404
 
-#define TCGETA         _IOR('t', 23, struct termio)
-#define TCSETA         _IOW('t', 24, struct termio)
-#define TCSETAW                _IOW('t', 25, struct termio)
-#define TCSETAF                _IOW('t', 28, struct termio)
+#define TCGETA         0x80127417      /* _IOR('t', 23, struct termio) */
+#define TCSETA         0x40127418      /* _IOW('t', 24, struct termio) */
+#define TCSETAW                0x40127419      /* _IOW('t', 25, struct termio) */
+#define TCSETAF                0x4012741C      /* _IOW('t', 28, struct termio) */
 
 #define TCSBRK         _IO('t', 29)
 #define TCXONC         _IO('t', 30)
 #define TCFLSH         _IO('t', 31)
 
-#define TIOCSWINSZ     _IOW('t', 103, struct winsize)
-#define TIOCGWINSZ     _IOR('t', 104, struct winsize)
+#define TIOCSWINSZ     0x40087467      /* _IOW('t', 103, struct winsize) */
+#define TIOCGWINSZ     0x80087468      /* _IOR('t', 104, struct winsize) */
 #define        TIOCSTART       _IO('t', 110)           /* start output, like ^Q */
 #define        TIOCSTOP        _IO('t', 111)           /* stop output, like ^S */
 #define TIOCOUTQ        _IOR('t', 115, int)     /* output queue size */
@@ -88,7 +88,6 @@
 #define TIOCSETD       _IOW('T', 35, int)
 #define TIOCGETD       _IOR('T', 36, int)
 #define TCSBRKP                _IOW('T', 37, int)   /* Needed for POSIX tcsendbreak()*/
-#define TIOCTTYGSTRUCT _IOR('T', 38, struct tty_struct) /* For debugging only*/
 #define TIOCSBRK       _IO('T', 39)         /* BSD compatibility */
 #define TIOCCBRK       _IO('T', 40)         /* BSD compatibility */
 #define TIOCGSID       _IOR('T', 41, pid_t) /* Return the session ID of FD*/
 #define TIOCSERGETLSR   _IOR('T', 89, unsigned int) /* Get line status reg. */
   /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
 # define TIOCSER_TEMT    0x01               /* Transmitter physically empty */
-#define TIOCSERGETMULTI _IOR('T', 90, struct serial_multiport_struct) /* Get multiport config  */
-#define TIOCSERSETMULTI _IOW('T', 91, struct serial_multiport_struct) /* Set multiport config */
+#define TIOCSERGETMULTI 0x80a8545a /* Get multiport config  */
+                       /* _IOR('T', 90, struct serial_multiport_struct) */
+#define TIOCSERSETMULTI 0x40a8545b /* Set multiport config */
+                       /* _IOW('T', 91, struct serial_multiport_struct) */
 
 #define TIOCMIWAIT     _IO('T', 92) /* wait for a change on serial input line(s) */
 #define TIOCGICOUNT    0x545D  /* read serial port inline interrupt counts */
index b9395529f02d465643091d71c4d6b6ca9650ff4b..8883fc877c5c93334cacfd29ffe6a12300bb0961 100644 (file)
@@ -739,7 +739,10 @@ __SYSCALL(334, sys_sched_setattr, 2)
 #define __NR_sched_getattr                     335
 __SYSCALL(335, sys_sched_getattr, 3)
 
-#define __NR_syscall_count                     336
+#define __NR_renameat2                         336
+__SYSCALL(336, sys_renameat2, 5)
+
+#define __NR_syscall_count                     337
 
 /*
  * sysxtensa syscall handler
index d4cef6039a5c1ab785d4dead614ad7c9f92d0d6d..890004af03a927fb8768a4d3e7878ccd3c6a1ddf 100644 (file)
@@ -8,6 +8,7 @@
  * this archive for more details.
  *
  * Copyright (C) 2001 - 2005 Tensilica, Inc.
+ * Copyright (C) 2014 Cadence Design Systems Inc.
  *
  * Rewritten by Chris Zankel <chris@zankel.net>
  *
@@ -174,6 +175,10 @@ ENTRY(fast_unaligned)
        s32i    a0, a2, PT_AREG2
        s32i    a3, a2, PT_AREG3
 
+       rsr     a3, excsave1
+       movi    a4, fast_unaligned_fixup
+       s32i    a4, a3, EXC_TABLE_FIXUP
+
        /* Keep value of SAR in a0 */
 
        rsr     a0, sar
@@ -225,10 +230,6 @@ ENTRY(fast_unaligned)
        addx8   a5, a6, a5
        jx      a5                      # jump into table
 
-       /* Invalid instruction, CRITICAL! */
-.Linvalid_instruction_load:
-       j       .Linvalid_instruction
-
        /* Load: Load memory address. */
 
 .Lload: movi   a3, ~3
@@ -272,18 +273,6 @@ ENTRY(fast_unaligned)
        /* Set target register. */
 
 1:
-
-#if XCHAL_HAVE_LOOPS
-       rsr     a5, lend                # check if we reached LEND
-       bne     a7, a5, 1f
-       rsr     a5, lcount              # and LCOUNT != 0
-       beqz    a5, 1f
-       addi    a5, a5, -1              # decrement LCOUNT and set
-       rsr     a7, lbeg                # set PC to LBEGIN
-       wsr     a5, lcount
-#endif
-
-1:     wsr     a7, epc1                # skip load instruction
        extui   a4, a4, INSN_T, 4       # extract target register
        movi    a5, .Lload_table
        addx8   a4, a4, a5
@@ -326,6 +315,35 @@ ENTRY(fast_unaligned)
        mov     a3, a14         ;       _j 1f;  .align 8
        mov     a3, a15         ;       _j 1f;  .align 8
 
+       /* We cannot handle this exception. */
+
+       .extern _kernel_exception
+.Linvalid_instruction_load:
+.Linvalid_instruction_store:
+
+       movi    a4, 0
+       rsr     a3, excsave1
+       s32i    a4, a3, EXC_TABLE_FIXUP
+
+       /* Restore a4...a8 and SAR, set SP, and jump to default exception. */
+
+       l32i    a8, a2, PT_AREG8
+       l32i    a7, a2, PT_AREG7
+       l32i    a6, a2, PT_AREG6
+       l32i    a5, a2, PT_AREG5
+       l32i    a4, a2, PT_AREG4
+       wsr     a0, sar
+       mov     a1, a2
+
+       rsr     a0, ps
+       bbsi.l  a0, PS_UM_BIT, 2f     # jump if user mode
+
+       movi    a0, _kernel_exception
+       jx      a0
+
+2:     movi    a0, _user_exception
+       jx      a0
+
 1:     # a7: instruction pointer, a4: instruction, a3: value
 
        movi    a6, 0                   # mask: ffffffff:00000000
@@ -353,17 +371,6 @@ ENTRY(fast_unaligned)
        /* Get memory address */
 
 1:
-#if XCHAL_HAVE_LOOPS
-       rsr     a4, lend                # check if we reached LEND
-       bne     a7, a4, 1f
-       rsr     a4, lcount              # and LCOUNT != 0
-       beqz    a4, 1f
-       addi    a4, a4, -1              # decrement LCOUNT and set
-       rsr     a7, lbeg                # set PC to LBEGIN
-       wsr     a4, lcount
-#endif
-
-1:     wsr     a7, epc1                # skip store instruction
        movi    a4, ~3
        and     a4, a4, a8              # align memory address
 
@@ -375,25 +382,25 @@ ENTRY(fast_unaligned)
 #endif
 
        __ssa8r a8
-       __src_b a7, a5, a6              # lo-mask  F..F0..0 (BE) 0..0F..F (LE)
+       __src_b a8, a5, a6              # lo-mask  F..F0..0 (BE) 0..0F..F (LE)
        __src_b a6, a6, a5              # hi-mask  0..0F..F (BE) F..F0..0 (LE)
 #ifdef UNALIGNED_USER_EXCEPTION
        l32e    a5, a4, -8
 #else
        l32i    a5, a4, 0               # load lower address word
 #endif
-       and     a5, a5, a7              # mask
-       __sh    a7, a3                  # shift value
-       or      a5, a5, a7              # or with original value
+       and     a5, a5, a8              # mask
+       __sh    a8, a3                  # shift value
+       or      a5, a5, a8              # or with original value
 #ifdef UNALIGNED_USER_EXCEPTION
        s32e    a5, a4, -8
-       l32e    a7, a4, -4
+       l32e    a8, a4, -4
 #else
        s32i    a5, a4, 0               # store
-       l32i    a7, a4, 4               # same for upper address word
+       l32i    a8, a4, 4               # same for upper address word
 #endif
        __sl    a5, a3
-       and     a6, a7, a6
+       and     a6, a8, a6
        or      a6, a6, a5
 #ifdef UNALIGNED_USER_EXCEPTION
        s32e    a6, a4, -4
@@ -401,9 +408,27 @@ ENTRY(fast_unaligned)
        s32i    a6, a4, 4
 #endif
 
-       /* Done. restore stack and return */
-
 .Lexit:
+#if XCHAL_HAVE_LOOPS
+       rsr     a4, lend                # check if we reached LEND
+       bne     a7, a4, 1f
+       rsr     a4, lcount              # and LCOUNT != 0
+       beqz    a4, 1f
+       addi    a4, a4, -1              # decrement LCOUNT and set
+       rsr     a7, lbeg                # set PC to LBEGIN
+       wsr     a4, lcount
+#endif
+
+1:     wsr     a7, epc1                # skip emulated instruction
+
+       /* Update icount if we're single-stepping in userspace. */
+       rsr     a4, icountlevel
+       beqz    a4, 1f
+       bgeui   a4, LOCKLEVEL + 1, 1f
+       rsr     a4, icount
+       addi    a4, a4, 1
+       wsr     a4, icount
+1:
        movi    a4, 0
        rsr     a3, excsave1
        s32i    a4, a3, EXC_TABLE_FIXUP
@@ -424,31 +449,40 @@ ENTRY(fast_unaligned)
        l32i    a2, a2, PT_AREG2
        rfe
 
-       /* We cannot handle this exception. */
+ENDPROC(fast_unaligned)
 
-       .extern _kernel_exception
-.Linvalid_instruction_store:
-.Linvalid_instruction:
+ENTRY(fast_unaligned_fixup)
 
-       /* Restore a4...a8 and SAR, set SP, and jump to default exception. */
+       l32i    a2, a3, EXC_TABLE_DOUBLE_SAVE
+       wsr     a3, excsave1
 
        l32i    a8, a2, PT_AREG8
        l32i    a7, a2, PT_AREG7
        l32i    a6, a2, PT_AREG6
        l32i    a5, a2, PT_AREG5
        l32i    a4, a2, PT_AREG4
+       l32i    a0, a2, PT_AREG2
+       xsr     a0, depc                        # restore depc and a0
        wsr     a0, sar
-       mov     a1, a2
+
+       rsr     a0, exccause
+       s32i    a0, a2, PT_DEPC                 # mark as a regular exception
 
        rsr     a0, ps
-       bbsi.l  a2, PS_UM_BIT, 1f     # jump if user mode
+       bbsi.l  a0, PS_UM_BIT, 1f               # jump if user mode
 
-       movi    a0, _kernel_exception
+       rsr     a0, exccause
+       addx4   a0, a0, a3                      # find entry in table
+       l32i    a0, a0, EXC_TABLE_FAST_KERNEL   # load handler
+       l32i    a3, a2, PT_AREG3
        jx      a0
-
-1:     movi    a0, _user_exception
+1:
+       rsr     a0, exccause
+       addx4   a0, a0, a3                      # find entry in table
+       l32i    a0, a0, EXC_TABLE_FAST_USER     # load handler
+       l32i    a3, a2, PT_AREG3
        jx      a0
 
-ENDPROC(fast_unaligned)
+ENDPROC(fast_unaligned_fixup)
 
 #endif /* XCHAL_UNALIGNED_LOAD_EXCEPTION || XCHAL_UNALIGNED_STORE_EXCEPTION */
index ef7f4990722b4fde3a175a0d524f82c3b2ce8b7b..82bbfa5a05b34389c0947b2846bc68d49282c2a7 100644 (file)
@@ -986,6 +986,8 @@ ENDPROC(fast_syscall_unrecoverable)
  *             j done
  */
 
+#ifdef CONFIG_FAST_SYSCALL_XTENSA
+
 #define TRY                                                            \
        .section __ex_table, "a";                                       \
        .word   66f, 67f;                                               \
@@ -1001,9 +1003,8 @@ ENTRY(fast_syscall_xtensa)
        movi    a7, 4                   # sizeof(unsigned int)
        access_ok a3, a7, a0, a2, .Leac # a0: scratch reg, a2: sp
 
-       addi    a6, a6, -1              # assuming SYS_XTENSA_ATOMIC_SET = 1
-       _bgeui  a6, SYS_XTENSA_COUNT - 1, .Lill
-       _bnei   a6, SYS_XTENSA_ATOMIC_CMP_SWP - 1, .Lnswp
+       _bgeui  a6, SYS_XTENSA_COUNT, .Lill
+       _bnei   a6, SYS_XTENSA_ATOMIC_CMP_SWP, .Lnswp
 
        /* Fall through for ATOMIC_CMP_SWP. */
 
@@ -1015,27 +1016,26 @@ TRY     s32i    a5, a3, 0               # different, modify value
        l32i    a7, a2, PT_AREG7        # restore a7
        l32i    a0, a2, PT_AREG0        # restore a0
        movi    a2, 1                   # and return 1
-       addi    a6, a6, 1               # restore a6 (really necessary?)
        rfe
 
 1:     l32i    a7, a2, PT_AREG7        # restore a7
        l32i    a0, a2, PT_AREG0        # restore a0
        movi    a2, 0                   # return 0 (note that we cannot set
-       addi    a6, a6, 1               # restore a6 (really necessary?)
        rfe
 
 .Lnswp:        /* Atomic set, add, and exg_add. */
 
 TRY    l32i    a7, a3, 0               # orig
+       addi    a6, a6, -SYS_XTENSA_ATOMIC_SET
        add     a0, a4, a7              # + arg
        moveqz  a0, a4, a6              # set
+       addi    a6, a6, SYS_XTENSA_ATOMIC_SET
 TRY    s32i    a0, a3, 0               # write new value
 
        mov     a0, a2
        mov     a2, a7
        l32i    a7, a0, PT_AREG7        # restore a7
        l32i    a0, a0, PT_AREG0        # restore a0
-       addi    a6, a6, 1               # restore a6 (really necessary?)
        rfe
 
 CATCH
@@ -1044,13 +1044,25 @@ CATCH
        movi    a2, -EFAULT
        rfe
 
-.Lill: l32i    a7, a2, PT_AREG0        # restore a7
+.Lill: l32i    a7, a2, PT_AREG7        # restore a7
        l32i    a0, a2, PT_AREG0        # restore a0
        movi    a2, -EINVAL
        rfe
 
 ENDPROC(fast_syscall_xtensa)
 
+#else /* CONFIG_FAST_SYSCALL_XTENSA */
+
+ENTRY(fast_syscall_xtensa)
+
+       l32i    a0, a2, PT_AREG0        # restore a0
+       movi    a2, -ENOSYS
+       rfe
+
+ENDPROC(fast_syscall_xtensa)
+
+#endif /* CONFIG_FAST_SYSCALL_XTENSA */
+
 
 /* fast_syscall_spill_registers.
  *
@@ -1066,6 +1078,8 @@ ENDPROC(fast_syscall_xtensa)
  * Note: We assume the stack pointer is EXC_TABLE_KSTK in the fixup handler.
  */
 
+#ifdef CONFIG_FAST_SYSCALL_SPILL_REGISTERS
+
 ENTRY(fast_syscall_spill_registers)
 
        /* Register a FIXUP handler (pass current wb as a parameter) */
@@ -1400,6 +1414,18 @@ ENTRY(fast_syscall_spill_registers_fixup_return)
 
 ENDPROC(fast_syscall_spill_registers_fixup_return)
 
+#else /* CONFIG_FAST_SYSCALL_SPILL_REGISTERS */
+
+ENTRY(fast_syscall_spill_registers)
+
+       l32i    a0, a2, PT_AREG0        # restore a0
+       movi    a2, -ENOSYS
+       rfe
+
+ENDPROC(fast_syscall_spill_registers)
+
+#endif /* CONFIG_FAST_SYSCALL_SPILL_REGISTERS */
+
 #ifdef CONFIG_MMU
 /*
  * We should never get here. Bail out!
@@ -1565,7 +1591,7 @@ ENTRY(fast_second_level_miss)
        rsr     a0, excvaddr
        bltu    a0, a3, 2f
 
-       addi    a1, a0, -(2 << (DCACHE_ALIAS_ORDER + PAGE_SHIFT))
+       addi    a1, a0, -TLBTEMP_SIZE
        bgeu    a1, a3, 2f
 
        /* Check if we have to restore an ITLB mapping. */
@@ -1820,7 +1846,6 @@ ENTRY(_switch_to)
 
        entry   a1, 16
 
-       mov     a10, a2                 # preserve 'prev' (a2)
        mov     a11, a3                 # and 'next' (a3)
 
        l32i    a4, a2, TASK_THREAD_INFO
@@ -1828,8 +1853,14 @@ ENTRY(_switch_to)
 
        save_xtregs_user a4 a6 a8 a9 a12 a13 THREAD_XTREGS_USER
 
-       s32i    a0, a10, THREAD_RA      # save return address
-       s32i    a1, a10, THREAD_SP      # save stack pointer
+#if THREAD_RA > 1020 || THREAD_SP > 1020
+       addi    a10, a2, TASK_THREAD
+       s32i    a0, a10, THREAD_RA - TASK_THREAD        # save return address
+       s32i    a1, a10, THREAD_SP - TASK_THREAD        # save stack pointer
+#else
+       s32i    a0, a2, THREAD_RA       # save return address
+       s32i    a1, a2, THREAD_SP       # save stack pointer
+#endif
 
        /* Disable ints while we manipulate the stack pointer. */
 
@@ -1870,7 +1901,6 @@ ENTRY(_switch_to)
        load_xtregs_user a5 a6 a8 a9 a12 a13 THREAD_XTREGS_USER
 
        wsr     a14, ps
-       mov     a2, a10                 # return 'prev'
        rsync
 
        retw
index 2d9cc6dbfd78acacd5bc63dbc140e02dbe0a4dc3..e8b76b8e4b2910a17435fd971da65138b97cbfde 100644 (file)
@@ -49,9 +49,8 @@ dma_alloc_coherent(struct device *dev,size_t size,dma_addr_t *handle,gfp_t flag)
 
        /* We currently don't support coherent memory outside KSEG */
 
-       if (ret < XCHAL_KSEG_CACHED_VADDR
-           || ret >= XCHAL_KSEG_CACHED_VADDR + XCHAL_KSEG_SIZE)
-               BUG();
+       BUG_ON(ret < XCHAL_KSEG_CACHED_VADDR ||
+              ret > XCHAL_KSEG_CACHED_VADDR + XCHAL_KSEG_SIZE - 1);
 
 
        if (ret != 0) {
@@ -68,10 +67,11 @@ EXPORT_SYMBOL(dma_alloc_coherent);
 void dma_free_coherent(struct device *hwdev, size_t size,
                         void *vaddr, dma_addr_t dma_handle)
 {
-       long addr=(long)vaddr+XCHAL_KSEG_CACHED_VADDR-XCHAL_KSEG_BYPASS_VADDR;
+       unsigned long addr = (unsigned long)vaddr +
+               XCHAL_KSEG_CACHED_VADDR - XCHAL_KSEG_BYPASS_VADDR;
 
-       if (addr < 0 || addr >= XCHAL_KSEG_SIZE)
-               BUG();
+       BUG_ON(addr < XCHAL_KSEG_CACHED_VADDR ||
+              addr > XCHAL_KSEG_CACHED_VADDR + XCHAL_KSEG_SIZE - 1);
 
        free_pages(addr, get_order(size));
 }
index 40b5a3771fb063fb02ffaa7fe07a426a3a684677..4d02e38514f5460cc9c3a65d7b4d390be1c9e3aa 100644 (file)
@@ -571,6 +571,7 @@ void flush_icache_range(unsigned long start, unsigned long end)
        };
        on_each_cpu(ipi_flush_icache_range, &fd, 1);
 }
+EXPORT_SYMBOL(flush_icache_range);
 
 /* ------------------------------------------------------------------------- */
 
index eebbfd8c26fc25121bced6cb18c074a55c6cb5f5..9d2f45f010ef7e9448e3837e873b617f0a493b23 100644 (file)
@@ -101,9 +101,8 @@ static dispatch_init_table_t __initdata dispatch_init_table[] = {
 #if XCHAL_UNALIGNED_LOAD_EXCEPTION || XCHAL_UNALIGNED_STORE_EXCEPTION
 #ifdef CONFIG_XTENSA_UNALIGNED_USER
 { EXCCAUSE_UNALIGNED,          USER,      fast_unaligned },
-#else
-{ EXCCAUSE_UNALIGNED,          0,         do_unaligned_user },
 #endif
+{ EXCCAUSE_UNALIGNED,          0,         do_unaligned_user },
 { EXCCAUSE_UNALIGNED,          KRNL,      fast_unaligned },
 #endif
 #ifdef CONFIG_MMU
@@ -264,7 +263,6 @@ do_illegal_instruction(struct pt_regs *regs)
  */
 
 #if XCHAL_UNALIGNED_LOAD_EXCEPTION || XCHAL_UNALIGNED_STORE_EXCEPTION
-#ifndef CONFIG_XTENSA_UNALIGNED_USER
 void
 do_unaligned_user (struct pt_regs *regs)
 {
@@ -286,7 +284,6 @@ do_unaligned_user (struct pt_regs *regs)
 
 }
 #endif
-#endif
 
 void
 do_debug(struct pt_regs *regs)
index 8453e6e398951b0d1864b6e570c8d7d63e45d356..1b397a902292f8224f27856f6ff14471fad1e6ff 100644 (file)
@@ -454,8 +454,14 @@ _DoubleExceptionVector_WindowOverflow:
        s32i    a0, a2, PT_DEPC
 
 _DoubleExceptionVector_handle_exception:
+       addi    a0, a0, -EXCCAUSE_UNALIGNED
+       beqz    a0, 2f
        addx4   a0, a0, a3
-       l32i    a0, a0, EXC_TABLE_FAST_USER
+       l32i    a0, a0, EXC_TABLE_FAST_USER + 4 * EXCCAUSE_UNALIGNED
+       xsr     a3, excsave1
+       jx      a0
+2:
+       movi    a0, user_exception
        xsr     a3, excsave1
        jx      a0
 
index d16db6df86f8e3d823ac2f189816d9889249323e..fc1bc2ba8d5deb34348e783d82f6e0a0b919828a 100644 (file)
@@ -269,13 +269,13 @@ SECTIONS
                  .UserExceptionVector.literal)
   SECTION_VECTOR (_DoubleExceptionVector_literal,
                  .DoubleExceptionVector.literal,
-                 DOUBLEEXC_VECTOR_VADDR - 40,
+                 DOUBLEEXC_VECTOR_VADDR - 48,
                  SIZEOF(.UserExceptionVector.text),
                  .UserExceptionVector.text)
   SECTION_VECTOR (_DoubleExceptionVector_text,
                  .DoubleExceptionVector.text,
                  DOUBLEEXC_VECTOR_VADDR,
-                 40,
+                 48,
                  .DoubleExceptionVector.literal)
 
   . = (LOADADDR( .DoubleExceptionVector.text ) + SIZEOF( .DoubleExceptionVector.text ) + 3) & ~ 3;
index 63cbb867dadd64d8907176f1bd60420f8a41217a..d75aa1476da7595d224c02576a8ee5fcb3fe716e 100644 (file)
  *
  */
 
-#if (DCACHE_WAY_SIZE > PAGE_SIZE) && defined(CONFIG_HIGHMEM)
-#error "HIGHMEM is not supported on cores with aliasing cache."
-#endif
+#if (DCACHE_WAY_SIZE > PAGE_SIZE)
+static inline void kmap_invalidate_coherent(struct page *page,
+                                           unsigned long vaddr)
+{
+       if (!DCACHE_ALIAS_EQ(page_to_phys(page), vaddr)) {
+               unsigned long kvaddr;
+
+               if (!PageHighMem(page)) {
+                       kvaddr = (unsigned long)page_to_virt(page);
+
+                       __invalidate_dcache_page(kvaddr);
+               } else {
+                       kvaddr = TLBTEMP_BASE_1 +
+                               (page_to_phys(page) & DCACHE_ALIAS_MASK);
+
+                       __invalidate_dcache_page_alias(kvaddr,
+                                                      page_to_phys(page));
+               }
+       }
+}
+
+static inline void *coherent_kvaddr(struct page *page, unsigned long base,
+                                   unsigned long vaddr, unsigned long *paddr)
+{
+       if (PageHighMem(page) || !DCACHE_ALIAS_EQ(page_to_phys(page), vaddr)) {
+               *paddr = page_to_phys(page);
+               return (void *)(base + (vaddr & DCACHE_ALIAS_MASK));
+       } else {
+               *paddr = 0;
+               return page_to_virt(page);
+       }
+}
+
+void clear_user_highpage(struct page *page, unsigned long vaddr)
+{
+       unsigned long paddr;
+       void *kvaddr = coherent_kvaddr(page, TLBTEMP_BASE_1, vaddr, &paddr);
+
+       pagefault_disable();
+       kmap_invalidate_coherent(page, vaddr);
+       set_bit(PG_arch_1, &page->flags);
+       clear_page_alias(kvaddr, paddr);
+       pagefault_enable();
+}
+
+void copy_user_highpage(struct page *dst, struct page *src,
+                       unsigned long vaddr, struct vm_area_struct *vma)
+{
+       unsigned long dst_paddr, src_paddr;
+       void *dst_vaddr = coherent_kvaddr(dst, TLBTEMP_BASE_1, vaddr,
+                                         &dst_paddr);
+       void *src_vaddr = coherent_kvaddr(src, TLBTEMP_BASE_2, vaddr,
+                                         &src_paddr);
+
+       pagefault_disable();
+       kmap_invalidate_coherent(dst, vaddr);
+       set_bit(PG_arch_1, &dst->flags);
+       copy_page_alias(dst_vaddr, src_vaddr, dst_paddr, src_paddr);
+       pagefault_enable();
+}
+
+#endif /* DCACHE_WAY_SIZE > PAGE_SIZE */
 
 #if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
 
@@ -103,7 +162,8 @@ void flush_dcache_page(struct page *page)
                if (!alias && !mapping)
                        return;
 
-               __flush_invalidate_dcache_page((long)page_address(page));
+               virt = TLBTEMP_BASE_1 + (phys & DCACHE_ALIAS_MASK);
+               __flush_invalidate_dcache_page_alias(virt, phys);
 
                virt = TLBTEMP_BASE_1 + (temp & DCACHE_ALIAS_MASK);
 
@@ -168,13 +228,12 @@ update_mmu_cache(struct vm_area_struct * vma, unsigned long addr, pte_t *ptep)
 #if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
 
        if (!PageReserved(page) && test_bit(PG_arch_1, &page->flags)) {
-
-               unsigned long paddr = (unsigned long) page_address(page);
                unsigned long phys = page_to_phys(page);
-               unsigned long tmp = TLBTEMP_BASE_1 + (addr & DCACHE_ALIAS_MASK);
-
-               __flush_invalidate_dcache_page(paddr);
+               unsigned long tmp;
 
+               tmp = TLBTEMP_BASE_1 + (phys & DCACHE_ALIAS_MASK);
+               __flush_invalidate_dcache_page_alias(tmp, phys);
+               tmp = TLBTEMP_BASE_1 + (addr & DCACHE_ALIAS_MASK);
                __flush_invalidate_dcache_page_alias(tmp, phys);
                __invalidate_icache_page_alias(tmp, phys);
 
index 17a8c0d6fd17e525d448e7e577e5fbcdd6a91f76..8cfb71ec0937369a8adf79a3d6e754f589cbba5f 100644 (file)
 
 static pte_t *kmap_pte;
 
+#if DCACHE_WAY_SIZE > PAGE_SIZE
+unsigned int last_pkmap_nr_arr[DCACHE_N_COLORS];
+wait_queue_head_t pkmap_map_wait_arr[DCACHE_N_COLORS];
+
+static void __init kmap_waitqueues_init(void)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(pkmap_map_wait_arr); ++i)
+               init_waitqueue_head(pkmap_map_wait_arr + i);
+}
+#else
+static inline void kmap_waitqueues_init(void)
+{
+}
+#endif
+
+static inline enum fixed_addresses kmap_idx(int type, unsigned long color)
+{
+       return (type + KM_TYPE_NR * smp_processor_id()) * DCACHE_N_COLORS +
+               color;
+}
+
 void *kmap_atomic(struct page *page)
 {
        enum fixed_addresses idx;
        unsigned long vaddr;
-       int type;
 
        pagefault_disable();
        if (!PageHighMem(page))
                return page_address(page);
 
-       type = kmap_atomic_idx_push();
-       idx = type + KM_TYPE_NR * smp_processor_id();
+       idx = kmap_idx(kmap_atomic_idx_push(),
+                      DCACHE_ALIAS(page_to_phys(page)));
        vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
 #ifdef CONFIG_DEBUG_HIGHMEM
-       BUG_ON(!pte_none(*(kmap_pte - idx)));
+       BUG_ON(!pte_none(*(kmap_pte + idx)));
 #endif
-       set_pte(kmap_pte - idx, mk_pte(page, PAGE_KERNEL_EXEC));
+       set_pte(kmap_pte + idx, mk_pte(page, PAGE_KERNEL_EXEC));
 
        return (void *)vaddr;
 }
@@ -38,12 +60,10 @@ EXPORT_SYMBOL(kmap_atomic);
 
 void __kunmap_atomic(void *kvaddr)
 {
-       int idx, type;
-
        if (kvaddr >= (void *)FIXADDR_START &&
            kvaddr < (void *)FIXADDR_TOP) {
-               type = kmap_atomic_idx();
-               idx = type + KM_TYPE_NR * smp_processor_id();
+               int idx = kmap_idx(kmap_atomic_idx(),
+                                  DCACHE_ALIAS((unsigned long)kvaddr));
 
                /*
                 * Force other mappings to Oops if they'll try to access this
@@ -51,7 +71,7 @@ void __kunmap_atomic(void *kvaddr)
                 * is a bad idea also, in case the page changes cacheability
                 * attributes or becomes a protected page in a hypervisor.
                 */
-               pte_clear(&init_mm, kvaddr, kmap_pte - idx);
+               pte_clear(&init_mm, kvaddr, kmap_pte + idx);
                local_flush_tlb_kernel_range((unsigned long)kvaddr,
                                             (unsigned long)kvaddr + PAGE_SIZE);
 
@@ -69,4 +89,5 @@ void __init kmap_init(void)
        /* cache the first kmap pte */
        kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN);
        kmap_pte = kmap_get_fixmap_pte(kmap_vstart);
+       kmap_waitqueues_init();
 }
index 1f68558dbcc2264f99f917fcb18659d90f46a8cb..11a01c3e9cea91ece949e93c0c7776bdb4826170 100644 (file)
@@ -110,41 +110,24 @@ ENTRY(__tlbtemp_mapping_start)
 #if (DCACHE_WAY_SIZE > PAGE_SIZE)
 
 /*
- * clear_user_page (void *addr, unsigned long vaddr, struct page *page)
- *                     a2              a3                 a4
+ * clear_page_alias(void *addr, unsigned long paddr)
+ *                     a2              a3
  */
 
-ENTRY(clear_user_page)
+ENTRY(clear_page_alias)
 
        entry   a1, 32
 
-       /* Mark page dirty and determine alias. */
+       /* Skip setting up a temporary DTLB if not aliased low page. */
 
-       movi    a7, (1 << PG_ARCH_1)
-       l32i    a5, a4, PAGE_FLAGS
-       xor     a6, a2, a3
-       extui   a3, a3, PAGE_SHIFT, DCACHE_ALIAS_ORDER
-       extui   a6, a6, PAGE_SHIFT, DCACHE_ALIAS_ORDER
-       or      a5, a5, a7
-       slli    a3, a3, PAGE_SHIFT
-       s32i    a5, a4, PAGE_FLAGS
+       movi    a5, PAGE_OFFSET
+       movi    a6, 0
+       beqz    a3, 1f
 
-       /* Skip setting up a temporary DTLB if not aliased. */
-
-       beqz    a6, 1f
-
-       /* Invalidate kernel page. */
-
-       mov     a10, a2
-       call8   __invalidate_dcache_page
-
-       /* Setup a temporary DTLB with the color of the VPN */
-
-       movi    a4, ((PAGE_KERNEL | _PAGE_HW_WRITE) - PAGE_OFFSET) & 0xffffffff
-       movi    a5, TLBTEMP_BASE_1                      # virt
-       add     a6, a2, a4                              # ppn
-       add     a2, a5, a3                              # add 'color'
+       /* Setup a temporary DTLB for the addr. */
 
+       addi    a6, a3, (PAGE_KERNEL | _PAGE_HW_WRITE)
+       mov     a4, a2
        wdtlb   a6, a2
        dsync
 
@@ -165,62 +148,43 @@ ENTRY(clear_user_page)
 
        /* We need to invalidate the temporary idtlb entry, if any. */
 
-1:     addi    a2, a2, -PAGE_SIZE
-       idtlb   a2
+1:     idtlb   a4
        dsync
 
        retw
 
-ENDPROC(clear_user_page)
+ENDPROC(clear_page_alias)
 
 /*
- * copy_page_user (void *to, void *from, unsigned long vaddr, struct page *page)
- *                    a2          a3           a4                  a5
+ * copy_page_alias(void *to, void *from,
+ *                     a2        a3
+ *                 unsigned long to_paddr, unsigned long from_paddr)
+ *                              a4                      a5
  */
 
-ENTRY(copy_user_page)
+ENTRY(copy_page_alias)
 
        entry   a1, 32
 
-       /* Mark page dirty and determine alias for destination. */
-
-       movi    a8, (1 << PG_ARCH_1)
-       l32i    a9, a5, PAGE_FLAGS
-       xor     a6, a2, a4
-       xor     a7, a3, a4
-       extui   a4, a4, PAGE_SHIFT, DCACHE_ALIAS_ORDER
-       extui   a6, a6, PAGE_SHIFT, DCACHE_ALIAS_ORDER
-       extui   a7, a7, PAGE_SHIFT, DCACHE_ALIAS_ORDER
-       or      a9, a9, a8
-       slli    a4, a4, PAGE_SHIFT
-       s32i    a9, a5, PAGE_FLAGS
-       movi    a5, ((PAGE_KERNEL | _PAGE_HW_WRITE) - PAGE_OFFSET) & 0xffffffff
-
-       beqz    a6, 1f
-
-       /* Invalidate dcache */
-
-       mov     a10, a2
-       call8   __invalidate_dcache_page
+       /* Skip setting up a temporary DTLB for destination if not aliased. */
 
-       /* Setup a temporary DTLB with a matching color. */
+       movi    a6, 0
+       movi    a7, 0
+       beqz    a4, 1f
 
-       movi    a8, TLBTEMP_BASE_1                      # base
-       add     a6, a2, a5                              # ppn
-       add     a2, a8, a4                              # add 'color'
+       /* Setup a temporary DTLB for destination. */
 
+       addi    a6, a4, (PAGE_KERNEL | _PAGE_HW_WRITE)
        wdtlb   a6, a2
        dsync
 
-       /* Skip setting up a temporary DTLB for destination if not aliased. */
+       /* Skip setting up a temporary DTLB for source if not aliased. */
 
-1:     beqz    a7, 1f
+1:     beqz    a5, 1f
 
-       /* Setup a temporary DTLB with a matching color. */
+       /* Setup a temporary DTLB for source. */
 
-       movi    a8, TLBTEMP_BASE_2                      # base
-       add     a7, a3, a5                              # ppn
-       add     a3, a8, a4
+       addi    a7, a5, PAGE_KERNEL
        addi    a8, a3, 1                               # way1
 
        wdtlb   a7, a8
@@ -271,7 +235,7 @@ ENTRY(copy_user_page)
 
        retw
 
-ENDPROC(copy_user_page)
+ENDPROC(copy_page_alias)
 
 #endif
 
@@ -300,6 +264,30 @@ ENTRY(__flush_invalidate_dcache_page_alias)
        retw
 
 ENDPROC(__flush_invalidate_dcache_page_alias)
+
+/*
+ * void __invalidate_dcache_page_alias (addr, phys)
+ *                                       a2    a3
+ */
+
+ENTRY(__invalidate_dcache_page_alias)
+
+       entry   sp, 16
+
+       movi    a7, 0                   # required for exception handler
+       addi    a6, a3, (PAGE_KERNEL | _PAGE_HW_WRITE)
+       mov     a4, a2
+       wdtlb   a6, a2
+       dsync
+
+       ___invalidate_dcache_page a2 a3
+
+       idtlb   a4
+       dsync
+
+       retw
+
+ENDPROC(__invalidate_dcache_page_alias)
 #endif
 
 ENTRY(__tlbtemp_mapping_itlb)
index 3429b483d9f85cd2495e01c8c0a11d05bc22e16c..abe4513eb0ddf072f628406eb8af2d13b2774678 100644 (file)
 #include <asm/io.h>
 
 #if defined(CONFIG_HIGHMEM)
-static void * __init init_pmd(unsigned long vaddr)
+static void * __init init_pmd(unsigned long vaddr, unsigned long n_pages)
 {
        pgd_t *pgd = pgd_offset_k(vaddr);
        pmd_t *pmd = pmd_offset(pgd, vaddr);
+       pte_t *pte;
+       unsigned long i;
 
-       if (pmd_none(*pmd)) {
-               unsigned i;
-               pte_t *pte = alloc_bootmem_low_pages(PAGE_SIZE);
+       n_pages = ALIGN(n_pages, PTRS_PER_PTE);
 
-               for (i = 0; i < 1024; i++)
-                       pte_clear(NULL, 0, pte + i);
+       pr_debug("%s: vaddr: 0x%08lx, n_pages: %ld\n",
+                __func__, vaddr, n_pages);
 
-               set_pmd(pmd, __pmd(((unsigned long)pte) & PAGE_MASK));
-               BUG_ON(pte != pte_offset_kernel(pmd, 0));
-               pr_debug("%s: vaddr: 0x%08lx, pmd: 0x%p, pte: 0x%p\n",
-                        __func__, vaddr, pmd, pte);
-               return pte;
-       } else {
-               return pte_offset_kernel(pmd, 0);
+       pte = alloc_bootmem_low_pages(n_pages * sizeof(pte_t));
+
+       for (i = 0; i < n_pages; ++i)
+               pte_clear(NULL, 0, pte + i);
+
+       for (i = 0; i < n_pages; i += PTRS_PER_PTE, ++pmd) {
+               pte_t *cur_pte = pte + i;
+
+               BUG_ON(!pmd_none(*pmd));
+               set_pmd(pmd, __pmd(((unsigned long)cur_pte) & PAGE_MASK));
+               BUG_ON(cur_pte != pte_offset_kernel(pmd, 0));
+               pr_debug("%s: pmd: 0x%p, pte: 0x%p\n",
+                        __func__, pmd, cur_pte);
        }
+       return pte;
 }
 
 static void __init fixedrange_init(void)
 {
-       BUILD_BUG_ON(FIXADDR_SIZE > PMD_SIZE);
-       init_pmd(__fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK);
+       init_pmd(__fix_to_virt(0), __end_of_fixed_addresses);
 }
 #endif
 
@@ -52,7 +58,7 @@ void __init paging_init(void)
        memset(swapper_pg_dir, 0, PAGE_SIZE);
 #ifdef CONFIG_HIGHMEM
        fixedrange_init();
-       pkmap_page_table = init_pmd(PKMAP_BASE);
+       pkmap_page_table = init_pmd(PKMAP_BASE, LAST_PKMAP);
        kmap_init();
 #endif
 }
index bc423f7b02da856a6987089b6750322c9b7cbfe4..f14b4abbebd89a0b812a67b06e3a9bb2dffb707b 100644 (file)
@@ -520,7 +520,7 @@ void bio_integrity_endio(struct bio *bio, int error)
         */
        if (error) {
                bio->bi_end_io = bip->bip_end_io;
-               bio_endio(bio, error);
+               bio_endio_nodec(bio, error);
 
                return;
        }
index c359d72e9d76f24a44b7c4b6b8c36c6677436191..bf930f481d437ac1b1731d32d453280309773445 100644 (file)
@@ -1252,7 +1252,6 @@ void blk_rq_set_block_pc(struct request *rq)
        rq->__sector = (sector_t) -1;
        rq->bio = rq->biotail = NULL;
        memset(rq->__cmd, 0, sizeof(rq->__cmd));
-       rq->cmd = rq->__cmd;
 }
 EXPORT_SYMBOL(blk_rq_set_block_pc);
 
index 5189cb1e478a6b283609006364c01f9f8e31d082..4aac82615a46fd2363d03d28007fc5cf6be53929 100644 (file)
@@ -112,18 +112,22 @@ static void blk_mq_usage_counter_release(struct percpu_ref *ref)
  */
 void blk_mq_freeze_queue(struct request_queue *q)
 {
+       bool freeze;
+
        spin_lock_irq(q->queue_lock);
-       q->mq_freeze_depth++;
+       freeze = !q->mq_freeze_depth++;
        spin_unlock_irq(q->queue_lock);
 
-       percpu_ref_kill(&q->mq_usage_counter);
-       blk_mq_run_queues(q, false);
+       if (freeze) {
+               percpu_ref_kill(&q->mq_usage_counter);
+               blk_mq_run_queues(q, false);
+       }
        wait_event(q->mq_freeze_wq, percpu_ref_is_zero(&q->mq_usage_counter));
 }
 
 static void blk_mq_unfreeze_queue(struct request_queue *q)
 {
-       bool wake = false;
+       bool wake;
 
        spin_lock_irq(q->queue_lock);
        wake = !--q->mq_freeze_depth;
@@ -172,6 +176,8 @@ static void blk_mq_rq_ctx_init(struct request_queue *q, struct blk_mq_ctx *ctx,
        /* tag was already set */
        rq->errors = 0;
 
+       rq->cmd = rq->__cmd;
+
        rq->extra_len = 0;
        rq->sense_len = 0;
        rq->resid_len = 0;
@@ -1068,13 +1074,17 @@ static void blk_mq_bio_to_request(struct request *rq, struct bio *bio)
                blk_account_io_start(rq, 1);
 }
 
+static inline bool hctx_allow_merges(struct blk_mq_hw_ctx *hctx)
+{
+       return (hctx->flags & BLK_MQ_F_SHOULD_MERGE) &&
+               !blk_queue_nomerges(hctx->queue);
+}
+
 static inline bool blk_mq_merge_queue_io(struct blk_mq_hw_ctx *hctx,
                                         struct blk_mq_ctx *ctx,
                                         struct request *rq, struct bio *bio)
 {
-       struct request_queue *q = hctx->queue;
-
-       if (!(hctx->flags & BLK_MQ_F_SHOULD_MERGE)) {
+       if (!hctx_allow_merges(hctx)) {
                blk_mq_bio_to_request(rq, bio);
                spin_lock(&ctx->lock);
 insert_rq:
@@ -1082,6 +1092,8 @@ insert_rq:
                spin_unlock(&ctx->lock);
                return false;
        } else {
+               struct request_queue *q = hctx->queue;
+
                spin_lock(&ctx->lock);
                if (!blk_mq_attempt_merge(q, ctx, bio)) {
                        blk_mq_bio_to_request(rq, bio);
@@ -1574,7 +1586,7 @@ static int blk_mq_init_hw_queues(struct request_queue *q,
                hctx->tags = set->tags[i];
 
                /*
-                * Allocate space for all possible cpus to avoid allocation in
+                * Allocate space for all possible cpus to avoid allocation at
                 * runtime
                 */
                hctx->ctxs = kmalloc_node(nr_cpu_ids * sizeof(void *),
@@ -1662,8 +1674,8 @@ static void blk_mq_map_swqueue(struct request_queue *q)
 
        queue_for_each_hw_ctx(q, hctx, i) {
                /*
-                * If not software queues are mapped to this hardware queue,
-                * disable it and free the request entries
+                * If no software queues are mapped to this hardware queue,
+                * disable it and free the request entries.
                 */
                if (!hctx->nr_ctx) {
                        struct blk_mq_tag_set *set = q->tag_set;
@@ -1713,14 +1725,10 @@ static void blk_mq_del_queue_tag_set(struct request_queue *q)
 {
        struct blk_mq_tag_set *set = q->tag_set;
 
-       blk_mq_freeze_queue(q);
-
        mutex_lock(&set->tag_list_lock);
        list_del_init(&q->tag_set_list);
        blk_mq_update_tag_set_depth(set);
        mutex_unlock(&set->tag_list_lock);
-
-       blk_mq_unfreeze_queue(q);
 }
 
 static void blk_mq_add_queue_tag_set(struct blk_mq_tag_set *set,
index cadc37841744ddb1ed0b481e97f82319ee47aefc..3f31cf9508e6204c144c2b665fb90aa67df3c9a2 100644 (file)
@@ -1272,15 +1272,22 @@ __cfq_group_service_tree_add(struct cfq_rb_root *st, struct cfq_group *cfqg)
        rb_insert_color(&cfqg->rb_node, &st->rb);
 }
 
+/*
+ * This has to be called only on activation of cfqg
+ */
 static void
 cfq_update_group_weight(struct cfq_group *cfqg)
 {
-       BUG_ON(!RB_EMPTY_NODE(&cfqg->rb_node));
-
        if (cfqg->new_weight) {
                cfqg->weight = cfqg->new_weight;
                cfqg->new_weight = 0;
        }
+}
+
+static void
+cfq_update_group_leaf_weight(struct cfq_group *cfqg)
+{
+       BUG_ON(!RB_EMPTY_NODE(&cfqg->rb_node));
 
        if (cfqg->new_leaf_weight) {
                cfqg->leaf_weight = cfqg->new_leaf_weight;
@@ -1299,7 +1306,12 @@ cfq_group_service_tree_add(struct cfq_rb_root *st, struct cfq_group *cfqg)
        /* add to the service tree */
        BUG_ON(!RB_EMPTY_NODE(&cfqg->rb_node));
 
-       cfq_update_group_weight(cfqg);
+       /*
+        * Update leaf_weight.  We cannot update weight at this point
+        * because cfqg might already have been activated and is
+        * contributing its current weight to the parent's child_weight.
+        */
+       cfq_update_group_leaf_weight(cfqg);
        __cfq_group_service_tree_add(st, cfqg);
 
        /*
@@ -1323,6 +1335,7 @@ cfq_group_service_tree_add(struct cfq_rb_root *st, struct cfq_group *cfqg)
         */
        while ((parent = cfqg_parent(pos))) {
                if (propagate) {
+                       cfq_update_group_weight(pos);
                        propagate = !parent->nr_active++;
                        parent->children_weight += pos->weight;
                }
index 51bf5155ee756a4ac479e9c49fcf88824b0aeedc..9b8eaeca6a794b5be8e732567aceffbe6ab6ebdb 100644 (file)
@@ -279,7 +279,6 @@ static int blk_complete_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr,
        r = blk_rq_unmap_user(bio);
        if (!ret)
                ret = r;
-       blk_put_request(rq);
 
        return ret;
 }
@@ -297,8 +296,6 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk,
 
        if (hdr->interface_id != 'S')
                return -EINVAL;
-       if (hdr->cmd_len > BLK_MAX_CDB)
-               return -EINVAL;
 
        if (hdr->dxfer_len > (queue_max_hw_sectors(q) << 9))
                return -EIO;
@@ -317,16 +314,23 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk,
        if (hdr->flags & SG_FLAG_Q_AT_HEAD)
                at_head = 1;
 
+       ret = -ENOMEM;
        rq = blk_get_request(q, writing ? WRITE : READ, GFP_KERNEL);
        if (!rq)
-               return -ENOMEM;
+               goto out;
        blk_rq_set_block_pc(rq);
 
-       if (blk_fill_sghdr_rq(q, rq, hdr, mode)) {
-               blk_put_request(rq);
-               return -EFAULT;
+       if (hdr->cmd_len > BLK_MAX_CDB) {
+               rq->cmd = kzalloc(hdr->cmd_len, GFP_KERNEL);
+               if (!rq->cmd)
+                       goto out_put_request;
        }
 
+       ret = -EFAULT;
+       if (blk_fill_sghdr_rq(q, rq, hdr, mode))
+               goto out_free_cdb;
+
+       ret = 0;
        if (hdr->iovec_count) {
                size_t iov_data_len;
                struct iovec *iov = NULL;
@@ -335,7 +339,7 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk,
                                            0, NULL, &iov);
                if (ret < 0) {
                        kfree(iov);
-                       goto out;
+                       goto out_free_cdb;
                }
 
                iov_data_len = ret;
@@ -358,7 +362,7 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk,
                                      GFP_KERNEL);
 
        if (ret)
-               goto out;
+               goto out_free_cdb;
 
        bio = rq->bio;
        memset(sense, 0, sizeof(sense));
@@ -376,9 +380,14 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk,
 
        hdr->duration = jiffies_to_msecs(jiffies - start_time);
 
-       return blk_complete_sghdr_rq(rq, hdr, bio);
-out:
+       ret = blk_complete_sghdr_rq(rq, hdr, bio);
+
+out_free_cdb:
+       if (rq->cmd != rq->__cmd)
+               kfree(rq->cmd);
+out_put_request:
        blk_put_request(rq);
+out:
        return ret;
 }
 
@@ -448,6 +457,11 @@ int sg_scsi_ioctl(struct request_queue *q, struct gendisk *disk, fmode_t mode,
        }
 
        rq = blk_get_request(q, in_len ? WRITE : READ, __GFP_WAIT);
+       if (!rq) {
+               err = -ENOMEM;
+               goto error;
+       }
+       blk_rq_set_block_pc(rq);
 
        cmdlen = COMMAND_SIZE(opcode);
 
@@ -501,7 +515,6 @@ int sg_scsi_ioctl(struct request_queue *q, struct gendisk *disk, fmode_t mode,
        memset(sense, 0, sizeof(sense));
        rq->sense = sense;
        rq->sense_len = 0;
-       blk_rq_set_block_pc(rq);
 
        blk_execute_rq(q, disk, rq, 0);
 
@@ -521,7 +534,8 @@ out:
        
 error:
        kfree(buffer);
-       blk_put_request(rq);
+       if (rq)
+               blk_put_request(rq);
        return err;
 }
 EXPORT_SYMBOL_GPL(sg_scsi_ioctl);
index 97eb001960b97774e89643f65711d2a68e6a3a8f..2f6e4fb1a1ea14c4a1bcba18618b0bdaf6e1cd9c 100644 (file)
@@ -121,6 +121,7 @@ static int public_key_verify_signature_2(const struct key *key,
 struct asymmetric_key_subtype public_key_subtype = {
        .owner                  = THIS_MODULE,
        .name                   = "public_key",
+       .name_len               = sizeof("public_key") - 1,
        .describe               = public_key_describe,
        .destroy                = public_key_destroy,
        .verify_signature       = public_key_verify_signature_2,
index 79175e6ea0b28493f26079d5a17926e0aab63984..2421f46184ce873076fe3cfc0f195a2d7bf4f902 100644 (file)
@@ -128,6 +128,7 @@ static int pefile_strip_sig_wrapper(const void *pebuf,
 {
        struct win_certificate wrapper;
        const u8 *pkcs7;
+       unsigned len;
 
        if (ctx->sig_len < sizeof(wrapper)) {
                pr_debug("Signature wrapper too short\n");
@@ -154,33 +155,49 @@ static int pefile_strip_sig_wrapper(const void *pebuf,
                return -ENOTSUPP;
        }
 
-       /* Looks like actual pkcs signature length is in wrapper->length.
-        * size obtained from data dir entries lists the total size of
-        * certificate table which is also aligned to octawrod boundary.
-        *
-        * So set signature length field appropriately.
+       /* It looks like the pkcs signature length in wrapper->length and the
+        * size obtained from the data dir entries, which lists the total size
+        * of certificate table, are both aligned to an octaword boundary, so
+        * we may have to deal with some padding.
         */
        ctx->sig_len = wrapper.length;
        ctx->sig_offset += sizeof(wrapper);
        ctx->sig_len -= sizeof(wrapper);
-       if (ctx->sig_len == 0) {
+       if (ctx->sig_len < 4) {
                pr_debug("Signature data missing\n");
                return -EKEYREJECTED;
        }
 
-       /* What's left should a PKCS#7 cert */
+       /* What's left should be a PKCS#7 cert */
        pkcs7 = pebuf + ctx->sig_offset;
-       if (pkcs7[0] == (ASN1_CONS_BIT | ASN1_SEQ)) {
-               if (pkcs7[1] == 0x82 &&
-                   pkcs7[2] == (((ctx->sig_len - 4) >> 8) & 0xff) &&
-                   pkcs7[3] ==  ((ctx->sig_len - 4)       & 0xff))
-                       return 0;
-               if (pkcs7[1] == 0x80)
-                       return 0;
-               if (pkcs7[1] > 0x82)
-                       return -EMSGSIZE;
+       if (pkcs7[0] != (ASN1_CONS_BIT | ASN1_SEQ))
+               goto not_pkcs7;
+
+       switch (pkcs7[1]) {
+       case 0 ... 0x7f:
+               len = pkcs7[1] + 2;
+               goto check_len;
+       case ASN1_INDEFINITE_LENGTH:
+               return 0;
+       case 0x81:
+               len = pkcs7[2] + 3;
+               goto check_len;
+       case 0x82:
+               len = ((pkcs7[2] << 8) | pkcs7[3]) + 4;
+               goto check_len;
+       case 0x83 ... 0xff:
+               return -EMSGSIZE;
+       default:
+               goto not_pkcs7;
        }
 
+check_len:
+       if (len <= ctx->sig_len) {
+               /* There may be padding */
+               ctx->sig_len = len;
+               return 0;
+       }
+not_pkcs7:
        pr_debug("Signature data not PKCS#7\n");
        return -ELIBBAD;
 }
index ce06149088c5b5366cd4c87b67dfffdb793fc7a6..9dfec48dd4e503b82994e50d2ae7d06768f84d61 100644 (file)
@@ -196,6 +196,17 @@ static struct lpss_device_desc byt_i2c_dev_desc = {
        .setup = lpss_i2c_setup,
 };
 
+static struct lpss_shared_clock bsw_pwm_clock = {
+       .name = "pwm_clk",
+       .rate = 19200000,
+};
+
+static struct lpss_device_desc bsw_pwm_dev_desc = {
+       .clk_required = true,
+       .save_ctx = true,
+       .shared_clock = &bsw_pwm_clock,
+};
+
 #else
 
 #define LPSS_ADDR(desc) (0UL)
@@ -225,6 +236,12 @@ static const struct acpi_device_id acpi_lpss_device_ids[] = {
        { "INT33B2", },
        { "INT33FC", },
 
+       /* Braswell LPSS devices */
+       { "80862288", LPSS_ADDR(bsw_pwm_dev_desc) },
+       { "8086228A", LPSS_ADDR(byt_uart_dev_desc) },
+       { "8086228E", LPSS_ADDR(byt_spi_dev_desc) },
+       { "808622C1", LPSS_ADDR(byt_i2c_dev_desc) },
+
        { "INT3430", LPSS_ADDR(lpt_dev_desc) },
        { "INT3431", LPSS_ADDR(lpt_dev_desc) },
        { "INT3432", LPSS_ADDR(lpt_i2c_dev_desc) },
index 68f725839eb6d61bf129664922b1b22d7bdb0d05..1b13b921dda933e373b3e237886e55269df94aa7 100644 (file)
@@ -316,6 +316,45 @@ acpi_ns_check_package(struct acpi_evaluate_info *info,
                    acpi_ns_check_package_list(info, package, elements, count);
                break;
 
+       case ACPI_PTYPE2_UUID_PAIR:
+
+               /* The package must contain pairs of (UUID + type) */
+
+               if (count & 1) {
+                       expected_count = count + 1;
+                       goto package_too_small;
+               }
+
+               while (count > 0) {
+                       status = acpi_ns_check_object_type(info, elements,
+                                                          package->ret_info.
+                                                          object_type1, 0);
+                       if (ACPI_FAILURE(status)) {
+                               return (status);
+                       }
+
+                       /* Validate length of the UUID buffer */
+
+                       if ((*elements)->buffer.length != 16) {
+                               ACPI_WARN_PREDEFINED((AE_INFO,
+                                                     info->full_pathname,
+                                                     info->node_flags,
+                                                     "Invalid length for UUID Buffer"));
+                               return (AE_AML_OPERAND_VALUE);
+                       }
+
+                       status = acpi_ns_check_object_type(info, elements + 1,
+                                                          package->ret_info.
+                                                          object_type2, 0);
+                       if (ACPI_FAILURE(status)) {
+                               return (status);
+                       }
+
+                       elements += 2;
+                       count -= 2;
+               }
+               break;
+
        default:
 
                /* Should not get here if predefined info table is correct */
index a66ab658abbc6d69af9ef07fb7e79209531df376..cb6066c809ea03dddec42b0871e22a67ef242726 100644 (file)
@@ -197,6 +197,8 @@ static bool advance_transaction(struct acpi_ec *ec)
                                t->rdata[t->ri++] = acpi_ec_read_data(ec);
                                if (t->rlen == t->ri) {
                                        t->flags |= ACPI_EC_COMMAND_COMPLETE;
+                                       if (t->command == ACPI_EC_COMMAND_QUERY)
+                                               pr_debug("hardware QR_EC completion\n");
                                        wakeup = true;
                                }
                        } else
@@ -208,7 +210,20 @@ static bool advance_transaction(struct acpi_ec *ec)
                }
                return wakeup;
        } else {
-               if ((status & ACPI_EC_FLAG_IBF) == 0) {
+               /*
+                * There is firmware refusing to respond QR_EC when SCI_EVT
+                * is not set, for which case, we complete the QR_EC
+                * without issuing it to the firmware.
+                * https://bugzilla.kernel.org/show_bug.cgi?id=86211
+                */
+               if (!(status & ACPI_EC_FLAG_SCI) &&
+                   (t->command == ACPI_EC_COMMAND_QUERY)) {
+                       t->flags |= ACPI_EC_COMMAND_POLL;
+                       t->rdata[t->ri++] = 0x00;
+                       t->flags |= ACPI_EC_COMMAND_COMPLETE;
+                       pr_debug("software QR_EC completion\n");
+                       wakeup = true;
+               } else if ((status & ACPI_EC_FLAG_IBF) == 0) {
                        acpi_ec_write_cmd(ec, t->command);
                        t->flags |= ACPI_EC_COMMAND_POLL;
                } else
@@ -288,11 +303,11 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
        /* following two actions should be kept atomic */
        ec->curr = t;
        start_transaction(ec);
-       if (ec->curr->command == ACPI_EC_COMMAND_QUERY)
-               clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
        spin_unlock_irqrestore(&ec->lock, tmp);
        ret = ec_poll(ec);
        spin_lock_irqsave(&ec->lock, tmp);
+       if (ec->curr->command == ACPI_EC_COMMAND_QUERY)
+               clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
        ec->curr = NULL;
        spin_unlock_irqrestore(&ec->lock, tmp);
        return ret;
@@ -1015,6 +1030,10 @@ static struct dmi_system_id ec_dmi_table[] __initdata = {
        DMI_MATCH(DMI_SYS_VENDOR, "Quanta"),
        DMI_MATCH(DMI_PRODUCT_NAME, "TW9/SW9"),}, NULL},
        {
+       ec_flag_msi, "Clevo W350etq", {
+       DMI_MATCH(DMI_SYS_VENDOR, "CLEVO CO."),
+       DMI_MATCH(DMI_PRODUCT_NAME, "W35_37ET"),}, NULL},
+       {
        ec_validate_ecdt, "ASUS hardware", {
        DMI_MATCH(DMI_BIOS_VENDOR, "ASUS") }, NULL},
        {
index c96887d5289eaed997e29eaab738f8bb4bb488ee..6e6b80eb0bba1e369d36308d5779ec3cc184c4a0 100644 (file)
@@ -484,6 +484,10 @@ void acpi_pci_irq_disable(struct pci_dev *dev)
        /* Keep IOAPIC pin configuration when suspending */
        if (dev->dev.power.is_prepared)
                return;
+#ifdef CONFIG_PM_RUNTIME
+       if (dev->dev.power.runtime_status == RPM_SUSPENDING)
+               return;
+#endif
 
        entry = acpi_pci_irq_lookup(dev, pin);
        if (!entry)
index 3dca36d4ad26ef22d6ecea66e166ae22cde9ab33..17f9ec501972ef208b505ed881173e2dac0cc2ea 100644 (file)
@@ -1071,9 +1071,9 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr)
 
        if (pr->id == 0 && cpuidle_get_driver() == &acpi_idle_driver) {
 
-               cpuidle_pause_and_lock();
                /* Protect against cpu-hotplug */
                get_online_cpus();
+               cpuidle_pause_and_lock();
 
                /* Disable all cpuidle devices */
                for_each_online_cpu(cpu) {
@@ -1100,8 +1100,8 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr)
                                cpuidle_enable_device(dev);
                        }
                }
-               put_online_cpus();
                cpuidle_resume_and_unlock();
+               put_online_cpus();
        }
 
        return 0;
index 0a817ad24f16f75853d34e11deb1a226ef3d9ed0..3bf7764659a4f5643557eb2aee4b5b327da4f88f 100644 (file)
@@ -667,8 +667,14 @@ static ssize_t
 acpi_device_sun_show(struct device *dev, struct device_attribute *attr,
                     char *buf) {
        struct acpi_device *acpi_dev = to_acpi_device(dev);
+       acpi_status status;
+       unsigned long long sun;
+
+       status = acpi_evaluate_integer(acpi_dev->handle, "_SUN", NULL, &sun);
+       if (ACPI_FAILURE(status))
+               return -ENODEV;
 
-       return sprintf(buf, "%lu\n", acpi_dev->pnp.sun);
+       return sprintf(buf, "%llu\n", sun);
 }
 static DEVICE_ATTR(sun, 0444, acpi_device_sun_show, NULL);
 
@@ -690,7 +696,6 @@ static int acpi_device_setup_files(struct acpi_device *dev)
 {
        struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
        acpi_status status;
-       unsigned long long sun;
        int result = 0;
 
        /*
@@ -731,14 +736,10 @@ static int acpi_device_setup_files(struct acpi_device *dev)
        if (dev->pnp.unique_id)
                result = device_create_file(&dev->dev, &dev_attr_uid);
 
-       status = acpi_evaluate_integer(dev->handle, "_SUN", NULL, &sun);
-       if (ACPI_SUCCESS(status)) {
-               dev->pnp.sun = (unsigned long)sun;
+       if (acpi_has_method(dev->handle, "_SUN")) {
                result = device_create_file(&dev->dev, &dev_attr_sun);
                if (result)
                        goto end;
-       } else {
-               dev->pnp.sun = (unsigned long)-1;
        }
 
        if (acpi_has_method(dev->handle, "_STA")) {
@@ -922,12 +923,17 @@ static void acpi_device_notify(acpi_handle handle, u32 event, void *data)
        device->driver->ops.notify(device, event);
 }
 
-static acpi_status acpi_device_notify_fixed(void *data)
+static void acpi_device_notify_fixed(void *data)
 {
        struct acpi_device *device = data;
 
        /* Fixed hardware devices have no handles */
        acpi_device_notify(NULL, ACPI_FIXED_HARDWARE_EVENT, device);
+}
+
+static acpi_status acpi_device_fixed_event(void *data)
+{
+       acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_device_notify_fixed, data);
        return AE_OK;
 }
 
@@ -938,12 +944,12 @@ static int acpi_device_install_notify_handler(struct acpi_device *device)
        if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON)
                status =
                    acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
-                                                    acpi_device_notify_fixed,
+                                                    acpi_device_fixed_event,
                                                     device);
        else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON)
                status =
                    acpi_install_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
-                                                    acpi_device_notify_fixed,
+                                                    acpi_device_fixed_event,
                                                     device);
        else
                status = acpi_install_notify_handler(device->handle,
@@ -960,10 +966,10 @@ static void acpi_device_remove_notify_handler(struct acpi_device *device)
 {
        if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON)
                acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
-                                               acpi_device_notify_fixed);
+                                               acpi_device_fixed_event);
        else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON)
                acpi_remove_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
-                                               acpi_device_notify_fixed);
+                                               acpi_device_fixed_event);
        else
                acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
                                           acpi_device_notify);
@@ -975,7 +981,7 @@ static int acpi_device_probe(struct device *dev)
        struct acpi_driver *acpi_drv = to_acpi_driver(dev->driver);
        int ret;
 
-       if (acpi_dev->handler)
+       if (acpi_dev->handler && !acpi_is_pnp_device(acpi_dev))
                return -EINVAL;
 
        if (!acpi_drv->ops.add)
index 826884392e6b4b9df067623cfad758c29ea954a7..fcbda105616eb703b87e50ee88650cd4dde72d78 100644 (file)
@@ -82,9 +82,9 @@ module_param(allow_duplicates, bool, 0644);
  * For Windows 8 systems: used to decide if video module
  * should skip registering backlight interface of its own.
  */
-static int use_native_backlight_param = 1;
+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 bool use_native_backlight_dmi = true;
 
 static int register_count;
 static struct mutex video_list_lock;
@@ -417,6 +417,12 @@ static int __init video_set_use_native_backlight(const struct dmi_system_id *d)
        return 0;
 }
 
+static int __init video_disable_native_backlight(const struct dmi_system_id *d)
+{
+       use_native_backlight_dmi = false;
+       return 0;
+}
+
 static struct dmi_system_id video_dmi_table[] __initdata = {
        /*
         * Broken _BQC workaround http://bugzilla.kernel.org/show_bug.cgi?id=13121
@@ -720,6 +726,41 @@ static struct dmi_system_id video_dmi_table[] __initdata = {
                DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook 8780w"),
                },
        },
+
+       /*
+        * These models have a working acpi_video backlight control, and using
+        * native backlight causes a regression where backlight does not work
+        * when userspace is not handling brightness key events. Disable
+        * native_backlight on these to fix this:
+        * https://bugzilla.kernel.org/show_bug.cgi?id=81691
+        */
+       {
+        .callback = video_disable_native_backlight,
+        .ident = "ThinkPad T420",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+               DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T420"),
+               },
+       },
+       {
+        .callback = video_disable_native_backlight,
+        .ident = "ThinkPad T520",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+               DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T520"),
+               },
+       },
+
+       /* The native backlight controls do not work on some older machines */
+       {
+        /* https://bugs.freedesktop.org/show_bug.cgi?id=81515 */
+        .callback = video_disable_native_backlight,
+        .ident = "HP ENVY 15 Notebook",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "HP ENVY 15 Notebook PC"),
+               },
+       },
        {}
 };
 
index a29f8012fb08483cfb67e47b9d104db1e7db4954..a0cc0edafc78e27a9b1cee2031d1a74e523425d2 100644 (file)
@@ -305,6 +305,14 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, 0x9c85), board_ahci }, /* Wildcat Point-LP RAID */
        { PCI_VDEVICE(INTEL, 0x9c87), board_ahci }, /* Wildcat Point-LP RAID */
        { PCI_VDEVICE(INTEL, 0x9c8f), board_ahci }, /* Wildcat Point-LP RAID */
+       { PCI_VDEVICE(INTEL, 0x8c82), board_ahci }, /* 9 Series AHCI */
+       { PCI_VDEVICE(INTEL, 0x8c83), board_ahci }, /* 9 Series AHCI */
+       { PCI_VDEVICE(INTEL, 0x8c84), board_ahci }, /* 9 Series RAID */
+       { PCI_VDEVICE(INTEL, 0x8c85), board_ahci }, /* 9 Series RAID */
+       { PCI_VDEVICE(INTEL, 0x8c86), board_ahci }, /* 9 Series RAID */
+       { PCI_VDEVICE(INTEL, 0x8c87), board_ahci }, /* 9 Series RAID */
+       { PCI_VDEVICE(INTEL, 0x8c8e), board_ahci }, /* 9 Series RAID */
+       { PCI_VDEVICE(INTEL, 0x8c8f), board_ahci }, /* 9 Series RAID */
 
        /* JMicron 360/1/3/5/6, match class to avoid IDE function */
        { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
@@ -442,6 +450,8 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x917a),
          .driver_data = board_ahci_yes_fbs },                  /* 88se9172 */
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9172),
+         .driver_data = board_ahci_yes_fbs },                  /* 88se9182 */
+       { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9182),
          .driver_data = board_ahci_yes_fbs },                  /* 88se9172 */
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9192),
          .driver_data = board_ahci_yes_fbs },                  /* 88se9172 on some Gigabyte */
@@ -1329,6 +1339,18 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        else if (pdev->vendor == 0x1c44 && pdev->device == 0x8000)
                ahci_pci_bar = AHCI_PCI_BAR_ENMOTUS;
 
+       /*
+        * The JMicron chip 361/363 contains one SATA controller and one
+        * PATA controller,for powering on these both controllers, we must
+        * follow the sequence one by one, otherwise one of them can not be
+        * powered on successfully, so here we disable the async suspend
+        * method for these chips.
+        */
+       if (pdev->vendor == PCI_VENDOR_ID_JMICRON &&
+               (pdev->device == PCI_DEVICE_ID_JMICRON_JMB363 ||
+               pdev->device == PCI_DEVICE_ID_JMICRON_JMB361))
+               device_disable_async_suspend(&pdev->dev);
+
        /* acquire resources */
        rc = pcim_enable_device(pdev);
        if (rc)
index fc3df47fca3547b46d71073e3e5b429c0b3d29e4..032904402c9509af14eafdc36993e8d6eb39ac88 100644 (file)
  */
 
 #include <linux/ahci_platform.h>
-#include <linux/reset.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
-#include <linux/tegra-powergate.h>
 #include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+
+#include <soc/tegra/fuse.h>
+#include <soc/tegra/pmc.h>
+
 #include "ahci.h"
 
 #define SATA_CONFIGURATION_0                           0x180
@@ -180,9 +183,12 @@ static int tegra_ahci_controller_init(struct ahci_host_priv *hpriv)
 
        /* Pad calibration */
 
-       /* FIXME Always use calibration 0. Change this to read the calibration
-        * fuse once the fuse driver has landed. */
-       val = 0;
+       ret = tegra_fuse_readl(FUSE_SATA_CALIB, &val);
+       if (ret) {
+               dev_err(&tegra->pdev->dev,
+                       "failed to read calibration fuse: %d\n", ret);
+               return ret;
+       }
 
        calib = tegra124_pad_calibration[val & FUSE_SATA_CALIB_MASK];
 
index bc281115490ba5064e5495e0a48883b1d14f744f..f03aab187f4da1cf16d3f2cb34642f4fcaad7434 100644 (file)
@@ -78,6 +78,9 @@
 #define CFG_MEM_RAM_SHUTDOWN           0x00000070
 #define BLOCK_MEM_RDY                  0x00000074
 
+/* Max retry for link down */
+#define MAX_LINK_DOWN_RETRY 3
+
 struct xgene_ahci_context {
        struct ahci_host_priv *hpriv;
        struct device *dev;
@@ -145,6 +148,14 @@ static unsigned int xgene_ahci_qc_issue(struct ata_queued_cmd *qc)
        return rc;
 }
 
+static bool xgene_ahci_is_memram_inited(struct xgene_ahci_context *ctx)
+{
+       void __iomem *diagcsr = ctx->csr_diag;
+
+       return (readl(diagcsr + CFG_MEM_RAM_SHUTDOWN) == 0 &&
+               readl(diagcsr + BLOCK_MEM_RDY) == 0xFFFFFFFF);
+}
+
 /**
  * xgene_ahci_read_id - Read ID data from the specified device
  * @dev: device
@@ -229,8 +240,11 @@ static void xgene_ahci_set_phy_cfg(struct xgene_ahci_context *ctx, int channel)
  * and Gen1 (1.5Gbps). Otherwise during long IO stress test, the PHY will
  * report disparity error and etc. In addition, during COMRESET, there can
  * be error reported in the register PORT_SCR_ERR. For SERR_DISPARITY and
- * SERR_10B_8B_ERR, the PHY receiver line must be reseted. The following
- * algorithm is followed to proper configure the hardware PHY during COMRESET:
+ * SERR_10B_8B_ERR, the PHY receiver line must be reseted. Also during long
+ * reboot cycle regression, sometimes the PHY reports link down even if the
+ * device is present because of speed negotiation failure. so need to retry
+ * the COMRESET to get the link up. The following algorithm is followed to
+ * proper configure the hardware PHY during COMRESET:
  *
  * Alg Part 1:
  * 1. Start the PHY at Gen3 speed (default setting)
@@ -246,9 +260,15 @@ static void xgene_ahci_set_phy_cfg(struct xgene_ahci_context *ctx, int channel)
  * Alg Part 2:
  * 1. On link up, if there are any SERR_DISPARITY and SERR_10B_8B_ERR error
  *    reported in the register PORT_SCR_ERR, then reset the PHY receiver line
- * 2. Go to Alg Part 3
+ * 2. Go to Alg Part 4
  *
  * Alg Part 3:
+ * 1. Check the PORT_SCR_STAT to see whether device presence detected but PHY
+ *    communication establishment failed and maximum link down attempts are
+ *    less than Max attempts 3 then goto Alg Part 1.
+ * 2. Go to Alg Part 4.
+ *
+ * Alg Part 4:
  * 1. Clear any pending from register PORT_SCR_ERR.
  *
  * NOTE: For the initial version, we will NOT support Gen1/Gen2. In addition
@@ -267,19 +287,27 @@ static int xgene_ahci_do_hardreset(struct ata_link *link,
        u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
        void __iomem *port_mmio = ahci_port_base(ap);
        struct ata_taskfile tf;
+       int link_down_retry = 0;
        int rc;
-       u32 val;
-
-       /* clear D2H reception area to properly wait for D2H FIS */
-       ata_tf_init(link->device, &tf);
-       tf.command = ATA_BUSY;
-       ata_tf_to_fis(&tf, 0, 0, d2h_fis);
-       rc = sata_link_hardreset(link, timing, deadline, online,
+       u32 val, sstatus;
+
+       do {
+               /* clear D2H reception area to properly wait for D2H FIS */
+               ata_tf_init(link->device, &tf);
+               tf.command = ATA_BUSY;
+               ata_tf_to_fis(&tf, 0, 0, d2h_fis);
+               rc = sata_link_hardreset(link, timing, deadline, online,
                                 ahci_check_ready);
+               if (*online) {
+                       val = readl(port_mmio + PORT_SCR_ERR);
+                       if (val & (SERR_DISPARITY | SERR_10B_8B_ERR))
+                               dev_warn(ctx->dev, "link has error\n");
+                       break;
+               }
 
-       val = readl(port_mmio + PORT_SCR_ERR);
-       if (val & (SERR_DISPARITY | SERR_10B_8B_ERR))
-               dev_warn(ctx->dev, "link has error\n");
+               sata_scr_read(link, SCR_STATUS, &sstatus);
+       } while (link_down_retry++ < MAX_LINK_DOWN_RETRY &&
+                (sstatus & 0xff) == 0x1);
 
        /* clear all errors if any pending */
        val = readl(port_mmio + PORT_SCR_ERR);
@@ -344,7 +372,7 @@ static struct ata_port_operations xgene_ahci_ops = {
 };
 
 static const struct ata_port_info xgene_ahci_port_info = {
-       .flags = AHCI_FLAG_COMMON | ATA_FLAG_NCQ,
+       .flags = AHCI_FLAG_COMMON,
        .pio_mask = ATA_PIO4,
        .udma_mask = ATA_UDMA6,
        .port_ops = &xgene_ahci_ops,
@@ -467,6 +495,11 @@ static int xgene_ahci_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
+       if (xgene_ahci_is_memram_inited(ctx)) {
+               dev_info(dev, "skip clock and PHY initialization\n");
+               goto skip_clk_phy;
+       }
+
        /* Due to errata, HW requires full toggle transition */
        rc = ahci_platform_enable_clks(hpriv);
        if (rc)
@@ -479,8 +512,8 @@ static int xgene_ahci_probe(struct platform_device *pdev)
 
        /* Configure the host controller */
        xgene_ahci_hw_init(hpriv);
-
-       hpriv->flags = AHCI_HFLAG_NO_PMP | AHCI_HFLAG_YES_NCQ;
+skip_clk_phy:
+       hpriv->flags = AHCI_HFLAG_NO_PMP | AHCI_HFLAG_NO_NCQ;
 
        rc = ahci_platform_init_host(pdev, hpriv, &xgene_ahci_port_info);
        if (rc)
index 893e30e9a9efab5662d5361e83051f9ac1c650c0..ffbe625e6fd2738726e77d42313aa9a09866ec4b 100644 (file)
@@ -340,6 +340,14 @@ static const struct pci_device_id piix_pci_tbl[] = {
        { 0x8086, 0x0F21, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata_byt },
        /* SATA Controller IDE (Coleto Creek) */
        { 0x8086, 0x23a6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+       /* SATA Controller IDE (9 Series) */
+       { 0x8086, 0x8c88, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata_snb },
+       /* SATA Controller IDE (9 Series) */
+       { 0x8086, 0x8c89, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata_snb },
+       /* SATA Controller IDE (9 Series) */
+       { 0x8086, 0x8c80, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
+       /* SATA Controller IDE (9 Series) */
+       { 0x8086, 0x8c81, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
 
        { }     /* terminate list */
 };
index dbdc5d32343f53f7ed96a94cf2d6d69258a54237..f3e7b9f894cd131daea921fbd0e149fcaccadaeb 100644 (file)
@@ -4228,7 +4228,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
        { "Micron_M500*",               NULL,   ATA_HORKAGE_NO_NCQ_TRIM, },
        { "Crucial_CT???M500SSD*",      NULL,   ATA_HORKAGE_NO_NCQ_TRIM, },
        { "Micron_M550*",               NULL,   ATA_HORKAGE_NO_NCQ_TRIM, },
-       { "Crucial_CT???M550SSD*",      NULL,   ATA_HORKAGE_NO_NCQ_TRIM, },
+       { "Crucial_CT*M550SSD*",        NULL,   ATA_HORKAGE_NO_NCQ_TRIM, },
 
        /*
         * Some WD SATA-I drives spin up and down erratically when the link
index 4d1a5d2c4287f2979c34a2913c0cb4018f573776..47e418b8c8baa0eee13b0a2843c25371a83bd338 100644 (file)
@@ -143,6 +143,18 @@ static int jmicron_init_one (struct pci_dev *pdev, const struct pci_device_id *i
        };
        const struct ata_port_info *ppi[] = { &info, NULL };
 
+       /*
+        * The JMicron chip 361/363 contains one SATA controller and one
+        * PATA controller,for powering on these both controllers, we must
+        * follow the sequence one by one, otherwise one of them can not be
+        * powered on successfully, so here we disable the async suspend
+        * method for these chips.
+        */
+       if (pdev->vendor == PCI_VENDOR_ID_JMICRON &&
+               (pdev->device == PCI_DEVICE_ID_JMICRON_JMB363 ||
+               pdev->device == PCI_DEVICE_ID_JMICRON_JMB361))
+               device_disable_async_suspend(&pdev->dev);
+
        return ata_pci_bmdma_init_one(pdev, ppi, &jmicron_sht, NULL, 0);
 }
 
index 2578fc16960ad1d1671ab554cbbc40d6f5810e60..1a24a5dc39400705e709853908070ff9a4e3f45b 100644 (file)
@@ -360,7 +360,7 @@ static int pata_s3c_wait_after_reset(struct ata_link *link,
 /*
  * pata_s3c_bus_softreset - PATA device software reset
  */
-static unsigned int pata_s3c_bus_softreset(struct ata_port *ap,
+static int pata_s3c_bus_softreset(struct ata_port *ap,
                unsigned long deadline)
 {
        struct ata_ioports *ioaddr = &ap->ioaddr;
index 4e006d74bef8c0599e11ddda98c8f37a90c839bb..7f4cb76ed9fac1c6ff51a5f91ad4df0468ac5096 100644 (file)
@@ -585,7 +585,7 @@ static int scc_wait_after_reset(struct ata_link *link, unsigned int devmask,
  *     Note: Original code is ata_bus_softreset().
  */
 
-static unsigned int scc_bus_softreset(struct ata_port *ap, unsigned int devmask,
+static int scc_bus_softreset(struct ata_port *ap, unsigned int devmask,
                                       unsigned long deadline)
 {
        struct ata_ioports *ioaddr = &ap->ioaddr;
@@ -599,9 +599,7 @@ static unsigned int scc_bus_softreset(struct ata_port *ap, unsigned int devmask,
        udelay(20);
        out_be32(ioaddr->ctl_addr, ap->ctl);
 
-       scc_wait_after_reset(&ap->link, devmask, deadline);
-
-       return 0;
+       return scc_wait_after_reset(&ap->link, devmask, deadline);
 }
 
 /**
@@ -618,7 +616,8 @@ static int scc_softreset(struct ata_link *link, unsigned int *classes,
 {
        struct ata_port *ap = link->ap;
        unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
-       unsigned int devmask = 0, err_mask;
+       unsigned int devmask = 0;
+       int rc;
        u8 err;
 
        DPRINTK("ENTER\n");
@@ -634,9 +633,9 @@ static int scc_softreset(struct ata_link *link, unsigned int *classes,
 
        /* issue bus reset */
        DPRINTK("about to softreset, devmask=%x\n", devmask);
-       err_mask = scc_bus_softreset(ap, devmask, deadline);
-       if (err_mask) {
-               ata_port_err(ap, "SRST failed (err_mask=0x%x)\n", err_mask);
+       rc = scc_bus_softreset(ap, devmask, deadline);
+       if (rc) {
+               ata_port_err(ap, "SRST failed (err_mask=0x%x)\n", rc);
                return -EIO;
        }
 
index 7d1326985bee8b4d3e9dcb326bf795622901bf49..bfc90b8547f23f1c243a4f1c6d7c00fc95f632a6 100644 (file)
@@ -146,6 +146,9 @@ struct regcache_ops {
        enum regcache_type type;
        int (*init)(struct regmap *map);
        int (*exit)(struct regmap *map);
+#ifdef CONFIG_DEBUG_FS
+       void (*debugfs_init)(struct regmap *map);
+#endif
        int (*read)(struct regmap *map, unsigned int reg, unsigned int *value);
        int (*write)(struct regmap *map, unsigned int reg, unsigned int value);
        int (*sync)(struct regmap *map, unsigned int min, unsigned int max);
index 6a7e4fa12854c8ac365edbe6dbf918c04d2ccd59..f3e8fe0cc65030a8fea51c00994a343df8220659 100644 (file)
@@ -194,10 +194,6 @@ static void rbtree_debugfs_init(struct regmap *map)
 {
        debugfs_create_file("rbtree", 0400, map->debugfs, map, &rbtree_fops);
 }
-#else
-static void rbtree_debugfs_init(struct regmap *map)
-{
-}
 #endif
 
 static int regcache_rbtree_init(struct regmap *map)
@@ -222,8 +218,6 @@ static int regcache_rbtree_init(struct regmap *map)
                        goto err;
        }
 
-       rbtree_debugfs_init(map);
-
        return 0;
 
 err:
@@ -532,6 +526,9 @@ struct regcache_ops regcache_rbtree_ops = {
        .name = "rbtree",
        .init = regcache_rbtree_init,
        .exit = regcache_rbtree_exit,
+#ifdef CONFIG_DEBUG_FS
+       .debugfs_init = rbtree_debugfs_init,
+#endif
        .read = regcache_rbtree_read,
        .write = regcache_rbtree_write,
        .sync = regcache_rbtree_sync,
index 29b4128da0b08ce6b8eda048557ed9093b07efa0..5617da6dc898b3edeff6f8b6cdca38fbab849900 100644 (file)
@@ -698,7 +698,7 @@ int regcache_sync_block(struct regmap *map, void *block,
                        unsigned int block_base, unsigned int start,
                        unsigned int end)
 {
-       if (regmap_can_raw_write(map))
+       if (regmap_can_raw_write(map) && !map->use_single_rw)
                return regcache_sync_block_raw(map, block, cache_present,
                                               block_base, start, end);
        else
index 45d812c0ea7751868d3d14d7691da6f74493b54a..65ea7b256b3eab603100bfe451383bb1fa339ae8 100644 (file)
@@ -538,6 +538,9 @@ void regmap_debugfs_init(struct regmap *map, const char *name)
 
                next = rb_next(&range_node->node);
        }
+
+       if (map->cache_ops && map->cache_ops->debugfs_init)
+               map->cache_ops->debugfs_init(map);
 }
 
 void regmap_debugfs_exit(struct regmap *map)
index 78f43fb2fe84647d5e97d5c9f6468cf6c8704187..1cf427bc0d4a8f0ddd9571b69f5dcc14a2167bdb 100644 (file)
@@ -109,7 +109,7 @@ bool regmap_readable(struct regmap *map, unsigned int reg)
 
 bool regmap_volatile(struct regmap *map, unsigned int reg)
 {
-       if (!regmap_readable(map, reg))
+       if (!map->format.format_write && !regmap_readable(map, reg))
                return false;
 
        if (map->volatile_reg)
index 11115bbe115cb120c778b4818d1e14a05f2e012e..004d6aa671cecbf82f0df9da6078f868683de361 100644 (file)
 #include <linux/serial_reg.h>
 #include <linux/time.h>
 
+enum bcma_boot_dev {
+       BCMA_BOOT_DEV_UNK = 0,
+       BCMA_BOOT_DEV_ROM,
+       BCMA_BOOT_DEV_PARALLEL,
+       BCMA_BOOT_DEV_SERIAL,
+       BCMA_BOOT_DEV_NAND,
+};
+
 static const char * const part_probes[] = { "bcm47xxpart", NULL };
 
 static struct physmap_flash_data bcma_pflash_data = {
@@ -229,11 +237,51 @@ u32 bcma_cpu_clock(struct bcma_drv_mips *mcore)
 }
 EXPORT_SYMBOL(bcma_cpu_clock);
 
+static enum bcma_boot_dev bcma_boot_dev(struct bcma_bus *bus)
+{
+       struct bcma_drv_cc *cc = &bus->drv_cc;
+       u8 cc_rev = cc->core->id.rev;
+
+       if (cc_rev == 42) {
+               struct bcma_device *core;
+
+               core = bcma_find_core(bus, BCMA_CORE_NS_ROM);
+               if (core) {
+                       switch (bcma_aread32(core, BCMA_IOST) &
+                               BCMA_NS_ROM_IOST_BOOT_DEV_MASK) {
+                       case BCMA_NS_ROM_IOST_BOOT_DEV_NOR:
+                               return BCMA_BOOT_DEV_SERIAL;
+                       case BCMA_NS_ROM_IOST_BOOT_DEV_NAND:
+                               return BCMA_BOOT_DEV_NAND;
+                       case BCMA_NS_ROM_IOST_BOOT_DEV_ROM:
+                       default:
+                               return BCMA_BOOT_DEV_ROM;
+                       }
+               }
+       } else {
+               if (cc_rev == 38) {
+                       if (cc->status & BCMA_CC_CHIPST_5357_NAND_BOOT)
+                               return BCMA_BOOT_DEV_NAND;
+                       else if (cc->status & BIT(5))
+                               return BCMA_BOOT_DEV_ROM;
+               }
+
+               if ((cc->capabilities & BCMA_CC_CAP_FLASHT) ==
+                   BCMA_CC_FLASHT_PARA)
+                       return BCMA_BOOT_DEV_PARALLEL;
+               else
+                       return BCMA_BOOT_DEV_SERIAL;
+       }
+
+       return BCMA_BOOT_DEV_SERIAL;
+}
+
 static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
 {
        struct bcma_bus *bus = mcore->core->bus;
        struct bcma_drv_cc *cc = &bus->drv_cc;
        struct bcma_pflash *pflash = &cc->pflash;
+       enum bcma_boot_dev boot_dev;
 
        switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
        case BCMA_CC_FLASHT_STSER:
@@ -269,6 +317,20 @@ static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
                        bcma_nflash_init(cc);
                }
        }
+
+       /* Determine flash type this SoC boots from */
+       boot_dev = bcma_boot_dev(bus);
+       switch (boot_dev) {
+       case BCMA_BOOT_DEV_PARALLEL:
+       case BCMA_BOOT_DEV_SERIAL:
+               /* TODO: Init NVRAM using BCMA_SOC_FLASH2 window */
+               break;
+       case BCMA_BOOT_DEV_NAND:
+               /* TODO: Init NVRAM using BCMA_SOC_FLASH1 window */
+               break;
+       default:
+               break;
+       }
 }
 
 void bcma_core_mips_early_init(struct bcma_drv_mips *mcore)
index 294a7dd2519028a21260579f6c25b5a9aff011f7..f032ed6dd459564ece3a6cf119070c72ca2991cc 100644 (file)
@@ -282,6 +282,7 @@ static const struct pci_device_id bcma_pci_bridge_tbl[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a9) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43aa) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) },
+       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 43227) },  /* 0xA8DB */
        { 0, },
 };
 MODULE_DEVICE_TABLE(pci, bcma_pci_bridge_tbl);
index 3475e600011a5c5ce0ec6ffe2b41f4f68b04c0e7..1edd7e06462135f4ecc2192b67f12852e2a5a77d 100644 (file)
@@ -134,12 +134,16 @@ static void bcma_host_soc_block_write(struct bcma_device *core,
 
 static u32 bcma_host_soc_aread32(struct bcma_device *core, u16 offset)
 {
+       if (WARN_ONCE(!core->io_wrap, "Accessed core has no wrapper/agent\n"))
+               return ~0;
        return readl(core->io_wrap + offset);
 }
 
 static void bcma_host_soc_awrite32(struct bcma_device *core, u16 offset,
                                  u32 value)
 {
+       if (WARN_ONCE(!core->io_wrap, "Accessed core has no wrapper/agent\n"))
+               return;
        writel(value, core->io_wrap + offset);
 }
 
index b4764c6bcf171ddb5273238fe9993d717ad18ec4..e9bd77249a4c91f329c163c647b20299d1f4a530 100644 (file)
@@ -421,10 +421,13 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
                core->io_addr = ioremap_nocache(core->addr, BCMA_CORE_SIZE);
                if (!core->io_addr)
                        return -ENOMEM;
-               core->io_wrap = ioremap_nocache(core->wrap, BCMA_CORE_SIZE);
-               if (!core->io_wrap) {
-                       iounmap(core->io_addr);
-                       return -ENOMEM;
+               if (core->wrap) {
+                       core->io_wrap = ioremap_nocache(core->wrap,
+                                                       BCMA_CORE_SIZE);
+                       if (!core->io_wrap) {
+                               iounmap(core->io_addr);
+                               return -ENOMEM;
+                       }
                }
        }
        return 0;
index c7d138eca731b638c324eaf30ae60007625c0f80..3598110d2cefcff5cc1b69319b8d1891f7f46a2f 100644 (file)
@@ -442,12 +442,15 @@ static int rd_nr;
 int rd_size = CONFIG_BLK_DEV_RAM_SIZE;
 static int max_part;
 static int part_shift;
+static int part_show = 0;
 module_param(rd_nr, int, S_IRUGO);
 MODULE_PARM_DESC(rd_nr, "Maximum number of brd devices");
 module_param(rd_size, int, S_IRUGO);
 MODULE_PARM_DESC(rd_size, "Size of each RAM disk in kbytes.");
 module_param(max_part, int, S_IRUGO);
 MODULE_PARM_DESC(max_part, "Maximum number of partitions per RAM disk");
+module_param(part_show, int, S_IRUGO);
+MODULE_PARM_DESC(part_show, "Control RAM disk visibility in /proc/partitions");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_BLOCKDEV_MAJOR(RAMDISK_MAJOR);
 MODULE_ALIAS("rd");
@@ -501,7 +504,8 @@ static struct brd_device *brd_alloc(int i)
        disk->fops              = &brd_fops;
        disk->private_data      = brd;
        disk->queue             = brd->brd_queue;
-       disk->flags |= GENHD_FL_SUPPRESS_PARTITION_INFO;
+       if (!part_show)
+               disk->flags |= GENHD_FL_SUPPRESS_PARTITION_INFO;
        sprintf(disk->disk_name, "ram%d", i);
        set_capacity(disk, rd_size * 2);
 
index ab3ea62e5dfc70dc0e62488290688f468d69cbcc..c4328d9d9981ed18c8d5c5decc5af9efe00338ee 100644 (file)
@@ -1203,7 +1203,6 @@ static struct platform_driver ace_platform_driver = {
        .probe = ace_probe,
        .remove = ace_remove,
        .driver = {
-               .owner = THIS_MODULE,
                .name = "xsysace",
                .of_match_table = ace_of_match,
        },
index dfa4024c448a6222d8d12ffb2f05e1976652fca0..d00831c3d73136dc06df360445e0d9590c752eed 100644 (file)
@@ -378,7 +378,6 @@ static int zram_decompress_page(struct zram *zram, char *mem, u32 index)
        /* Should NEVER happen. Return bio error if it does. */
        if (unlikely(ret)) {
                pr_err("Decompression failed! err=%d, page=%u\n", ret, index);
-               atomic64_inc(&zram->stats.failed_reads);
                return ret;
        }
 
@@ -547,8 +546,6 @@ out:
                zcomp_strm_release(zram->comp, zstrm);
        if (is_partial_io(bvec))
                kfree(uncmem);
-       if (ret)
-               atomic64_inc(&zram->stats.failed_writes);
        return ret;
 }
 
@@ -566,6 +563,13 @@ static int zram_bvec_rw(struct zram *zram, struct bio_vec *bvec, u32 index,
                ret = zram_bvec_write(zram, bvec, index, offset);
        }
 
+       if (unlikely(ret)) {
+               if (rw == READ)
+                       atomic64_inc(&zram->stats.failed_reads);
+               else
+                       atomic64_inc(&zram->stats.failed_writes);
+       }
+
        return ret;
 }
 
index 5b0afde729cd885286f48d31991f7bc98f44328b..e0f725c87cc617b4ade4c7574c18fa6ce15ca828 100644 (file)
@@ -84,7 +84,7 @@ struct zram_stats {
        atomic64_t compr_data_size;     /* compressed size of pages stored */
        atomic64_t num_reads;   /* failed + successful */
        atomic64_t num_writes;  /* --do-- */
-       atomic64_t failed_reads;        /* should NEVER! happen */
+       atomic64_t failed_reads;        /* can happen when memory is too low */
        atomic64_t failed_writes;       /* can happen when memory is too low */
        atomic64_t invalid_io;  /* non-page-aligned I/O requests */
        atomic64_t notify_free; /* no. of swap slot free notifications */
index a0d7355ef1275e865ad09d6e3503c953111cf4fd..d85ced27ebd58f5a40b1881032daced2aedf82b0 100644 (file)
@@ -88,6 +88,7 @@ static const struct usb_device_id ath3k_table[] = {
        { USB_DEVICE(0x04CA, 0x300b) },
        { USB_DEVICE(0x0930, 0x0219) },
        { USB_DEVICE(0x0930, 0x0220) },
+       { USB_DEVICE(0x0930, 0x0227) },
        { USB_DEVICE(0x0b05, 0x17d0) },
        { USB_DEVICE(0x0CF3, 0x0036) },
        { USB_DEVICE(0x0CF3, 0x3004) },
@@ -138,6 +139,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = {
        { USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0930, 0x0227), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0CF3, 0x0036), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
index dfa5043e68bacc9de66f6ce12c565fb8f410f4b1..35e63aaa6f803e423a39e532adeff717b7279cb3 100644 (file)
@@ -61,7 +61,7 @@ MODULE_LICENSE("GPL");
 /* ======================== Local structures ======================== */
 
 
-typedef struct bluecard_info_t {
+struct bluecard_info {
        struct pcmcia_device *p_dev;
 
        struct hci_dev *hdev;
@@ -78,7 +78,7 @@ typedef struct bluecard_info_t {
 
        unsigned char ctrl_reg;
        unsigned long hw_state;         /* Status of the hardware and LED control */
-} bluecard_info_t;
+};
 
 
 static int bluecard_config(struct pcmcia_device *link);
@@ -157,7 +157,7 @@ static void bluecard_detach(struct pcmcia_device *p_dev);
 
 static void bluecard_activity_led_timeout(u_long arg)
 {
-       bluecard_info_t *info = (bluecard_info_t *)arg;
+       struct bluecard_info *info = (struct bluecard_info *)arg;
        unsigned int iobase = info->p_dev->resource[0]->start;
 
        if (!test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state)))
@@ -173,7 +173,7 @@ static void bluecard_activity_led_timeout(u_long arg)
 }
 
 
-static void bluecard_enable_activity_led(bluecard_info_t *info)
+static void bluecard_enable_activity_led(struct bluecard_info *info)
 {
        unsigned int iobase = info->p_dev->resource[0]->start;
 
@@ -215,7 +215,7 @@ static int bluecard_write(unsigned int iobase, unsigned int offset, __u8 *buf, i
 }
 
 
-static void bluecard_write_wakeup(bluecard_info_t *info)
+static void bluecard_write_wakeup(struct bluecard_info *info)
 {
        if (!info) {
                BT_ERR("Unknown device");
@@ -368,7 +368,8 @@ static int bluecard_read(unsigned int iobase, unsigned int offset, __u8 *buf, in
 }
 
 
-static void bluecard_receive(bluecard_info_t *info, unsigned int offset)
+static void bluecard_receive(struct bluecard_info *info,
+                            unsigned int offset)
 {
        unsigned int iobase;
        unsigned char buf[31];
@@ -497,7 +498,7 @@ static void bluecard_receive(bluecard_info_t *info, unsigned int offset)
 
 static irqreturn_t bluecard_interrupt(int irq, void *dev_inst)
 {
-       bluecard_info_t *info = dev_inst;
+       struct bluecard_info *info = dev_inst;
        unsigned int iobase;
        unsigned char reg;
 
@@ -562,7 +563,7 @@ static irqreturn_t bluecard_interrupt(int irq, void *dev_inst)
 
 static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud)
 {
-       bluecard_info_t *info = hci_get_drvdata(hdev);
+       struct bluecard_info *info = hci_get_drvdata(hdev);
        struct sk_buff *skb;
 
        /* Ericsson baud rate command */
@@ -611,7 +612,7 @@ static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud)
 
 static int bluecard_hci_flush(struct hci_dev *hdev)
 {
-       bluecard_info_t *info = hci_get_drvdata(hdev);
+       struct bluecard_info *info = hci_get_drvdata(hdev);
 
        /* Drop TX queue */
        skb_queue_purge(&(info->txq));
@@ -622,7 +623,7 @@ static int bluecard_hci_flush(struct hci_dev *hdev)
 
 static int bluecard_hci_open(struct hci_dev *hdev)
 {
-       bluecard_info_t *info = hci_get_drvdata(hdev);
+       struct bluecard_info *info = hci_get_drvdata(hdev);
 
        if (test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state)))
                bluecard_hci_set_baud_rate(hdev, DEFAULT_BAUD_RATE);
@@ -643,7 +644,7 @@ static int bluecard_hci_open(struct hci_dev *hdev)
 
 static int bluecard_hci_close(struct hci_dev *hdev)
 {
-       bluecard_info_t *info = hci_get_drvdata(hdev);
+       struct bluecard_info *info = hci_get_drvdata(hdev);
 
        if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
                return 0;
@@ -663,7 +664,7 @@ static int bluecard_hci_close(struct hci_dev *hdev)
 
 static int bluecard_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
 {
-       bluecard_info_t *info = hci_get_drvdata(hdev);
+       struct bluecard_info *info = hci_get_drvdata(hdev);
 
        switch (bt_cb(skb)->pkt_type) {
        case HCI_COMMAND_PKT:
@@ -691,7 +692,7 @@ static int bluecard_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
 /* ======================== Card services HCI interaction ======================== */
 
 
-static int bluecard_open(bluecard_info_t *info)
+static int bluecard_open(struct bluecard_info *info)
 {
        unsigned int iobase = info->p_dev->resource[0]->start;
        struct hci_dev *hdev;
@@ -806,7 +807,7 @@ static int bluecard_open(bluecard_info_t *info)
 }
 
 
-static int bluecard_close(bluecard_info_t *info)
+static int bluecard_close(struct bluecard_info *info)
 {
        unsigned int iobase = info->p_dev->resource[0]->start;
        struct hci_dev *hdev = info->hdev;
@@ -833,7 +834,7 @@ static int bluecard_close(bluecard_info_t *info)
 
 static int bluecard_probe(struct pcmcia_device *link)
 {
-       bluecard_info_t *info;
+       struct bluecard_info *info;
 
        /* Create new info device */
        info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
@@ -857,7 +858,7 @@ static void bluecard_detach(struct pcmcia_device *link)
 
 static int bluecard_config(struct pcmcia_device *link)
 {
-       bluecard_info_t *info = link->priv;
+       struct bluecard_info *info = link->priv;
        int i, n;
 
        link->config_index = 0x20;
@@ -897,7 +898,7 @@ failed:
 
 static void bluecard_release(struct pcmcia_device *link)
 {
-       bluecard_info_t *info = link->priv;
+       struct bluecard_info *info = link->priv;
 
        bluecard_close(info);
 
index 1d82721cf9c67e05653f00f6ae93e20d482c9ff4..4f7e8d400bc01a178bcbfcf499340b40545fb54f 100644 (file)
@@ -67,7 +67,7 @@ MODULE_FIRMWARE("BT3CPCC.bin");
 /* ======================== Local structures ======================== */
 
 
-typedef struct bt3c_info_t {
+struct bt3c_info {
        struct pcmcia_device *p_dev;
 
        struct hci_dev *hdev;
@@ -80,7 +80,7 @@ typedef struct bt3c_info_t {
        unsigned long rx_state;
        unsigned long rx_count;
        struct sk_buff *rx_skb;
-} bt3c_info_t;
+};
 
 
 static int bt3c_config(struct pcmcia_device *link);
@@ -175,7 +175,7 @@ static int bt3c_write(unsigned int iobase, int fifo_size, __u8 *buf, int len)
 }
 
 
-static void bt3c_write_wakeup(bt3c_info_t *info)
+static void bt3c_write_wakeup(struct bt3c_info *info)
 {
        if (!info) {
                BT_ERR("Unknown device");
@@ -214,7 +214,7 @@ static void bt3c_write_wakeup(bt3c_info_t *info)
 }
 
 
-static void bt3c_receive(bt3c_info_t *info)
+static void bt3c_receive(struct bt3c_info *info)
 {
        unsigned int iobase;
        int size = 0, avail;
@@ -336,7 +336,7 @@ static void bt3c_receive(bt3c_info_t *info)
 
 static irqreturn_t bt3c_interrupt(int irq, void *dev_inst)
 {
-       bt3c_info_t *info = dev_inst;
+       struct bt3c_info *info = dev_inst;
        unsigned int iobase;
        int iir;
        irqreturn_t r = IRQ_NONE;
@@ -388,7 +388,7 @@ static irqreturn_t bt3c_interrupt(int irq, void *dev_inst)
 
 static int bt3c_hci_flush(struct hci_dev *hdev)
 {
-       bt3c_info_t *info = hci_get_drvdata(hdev);
+       struct bt3c_info *info = hci_get_drvdata(hdev);
 
        /* Drop TX queue */
        skb_queue_purge(&(info->txq));
@@ -418,7 +418,7 @@ static int bt3c_hci_close(struct hci_dev *hdev)
 
 static int bt3c_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
 {
-       bt3c_info_t *info = hci_get_drvdata(hdev);
+       struct bt3c_info *info = hci_get_drvdata(hdev);
        unsigned long flags;
 
        switch (bt_cb(skb)->pkt_type) {
@@ -451,7 +451,8 @@ static int bt3c_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
 /* ======================== Card services HCI interaction ======================== */
 
 
-static int bt3c_load_firmware(bt3c_info_t *info, const unsigned char *firmware,
+static int bt3c_load_firmware(struct bt3c_info *info,
+                             const unsigned char *firmware,
                              int count)
 {
        char *ptr = (char *) firmware;
@@ -536,7 +537,7 @@ error:
 }
 
 
-static int bt3c_open(bt3c_info_t *info)
+static int bt3c_open(struct bt3c_info *info)
 {
        const struct firmware *firmware;
        struct hci_dev *hdev;
@@ -603,7 +604,7 @@ error:
 }
 
 
-static int bt3c_close(bt3c_info_t *info)
+static int bt3c_close(struct bt3c_info *info)
 {
        struct hci_dev *hdev = info->hdev;
 
@@ -620,7 +621,7 @@ static int bt3c_close(bt3c_info_t *info)
 
 static int bt3c_probe(struct pcmcia_device *link)
 {
-       bt3c_info_t *info;
+       struct bt3c_info *info;
 
        /* Create new info device */
        info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
@@ -683,7 +684,7 @@ static int bt3c_check_config_notpicky(struct pcmcia_device *p_dev,
 
 static int bt3c_config(struct pcmcia_device *link)
 {
-       bt3c_info_t *info = link->priv;
+       struct bt3c_info *info = link->priv;
        int i;
        unsigned long try;
 
@@ -724,7 +725,7 @@ failed:
 
 static void bt3c_release(struct pcmcia_device *link)
 {
-       bt3c_info_t *info = link->priv;
+       struct bt3c_info *info = link->priv;
 
        bt3c_close(info);
 
index fb948f02eda5b1747a7ca7604133daf88a719ef1..abb4d2106db464198c328af1069342bd36d64d80 100644 (file)
@@ -62,7 +62,7 @@ MODULE_LICENSE("GPL");
 /* ======================== Local structures ======================== */
 
 
-typedef struct btuart_info_t {
+struct btuart_info {
        struct pcmcia_device *p_dev;
 
        struct hci_dev *hdev;
@@ -75,7 +75,7 @@ typedef struct btuart_info_t {
        unsigned long rx_state;
        unsigned long rx_count;
        struct sk_buff *rx_skb;
-} btuart_info_t;
+};
 
 
 static int btuart_config(struct pcmcia_device *link);
@@ -127,7 +127,7 @@ static int btuart_write(unsigned int iobase, int fifo_size, __u8 *buf, int len)
 }
 
 
-static void btuart_write_wakeup(btuart_info_t *info)
+static void btuart_write_wakeup(struct btuart_info *info)
 {
        if (!info) {
                BT_ERR("Unknown device");
@@ -172,7 +172,7 @@ static void btuart_write_wakeup(btuart_info_t *info)
 }
 
 
-static void btuart_receive(btuart_info_t *info)
+static void btuart_receive(struct btuart_info *info)
 {
        unsigned int iobase;
        int boguscount = 0;
@@ -286,7 +286,7 @@ static void btuart_receive(btuart_info_t *info)
 
 static irqreturn_t btuart_interrupt(int irq, void *dev_inst)
 {
-       btuart_info_t *info = dev_inst;
+       struct btuart_info *info = dev_inst;
        unsigned int iobase;
        int boguscount = 0;
        int iir, lsr;
@@ -340,7 +340,8 @@ static irqreturn_t btuart_interrupt(int irq, void *dev_inst)
 }
 
 
-static void btuart_change_speed(btuart_info_t *info, unsigned int speed)
+static void btuart_change_speed(struct btuart_info *info,
+                               unsigned int speed)
 {
        unsigned long flags;
        unsigned int iobase;
@@ -397,7 +398,7 @@ static void btuart_change_speed(btuart_info_t *info, unsigned int speed)
 
 static int btuart_hci_flush(struct hci_dev *hdev)
 {
-       btuart_info_t *info = hci_get_drvdata(hdev);
+       struct btuart_info *info = hci_get_drvdata(hdev);
 
        /* Drop TX queue */
        skb_queue_purge(&(info->txq));
@@ -427,7 +428,7 @@ static int btuart_hci_close(struct hci_dev *hdev)
 
 static int btuart_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
 {
-       btuart_info_t *info = hci_get_drvdata(hdev);
+       struct btuart_info *info = hci_get_drvdata(hdev);
 
        switch (bt_cb(skb)->pkt_type) {
        case HCI_COMMAND_PKT:
@@ -455,7 +456,7 @@ static int btuart_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
 /* ======================== Card services HCI interaction ======================== */
 
 
-static int btuart_open(btuart_info_t *info)
+static int btuart_open(struct btuart_info *info)
 {
        unsigned long flags;
        unsigned int iobase = info->p_dev->resource[0]->start;
@@ -521,7 +522,7 @@ static int btuart_open(btuart_info_t *info)
 }
 
 
-static int btuart_close(btuart_info_t *info)
+static int btuart_close(struct btuart_info *info)
 {
        unsigned long flags;
        unsigned int iobase = info->p_dev->resource[0]->start;
@@ -550,7 +551,7 @@ static int btuart_close(btuart_info_t *info)
 
 static int btuart_probe(struct pcmcia_device *link)
 {
-       btuart_info_t *info;
+       struct btuart_info *info;
 
        /* Create new info device */
        info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
@@ -613,7 +614,7 @@ static int btuart_check_config_notpicky(struct pcmcia_device *p_dev,
 
 static int btuart_config(struct pcmcia_device *link)
 {
-       btuart_info_t *info = link->priv;
+       struct btuart_info *info = link->priv;
        int i;
        int try;
 
@@ -654,7 +655,7 @@ failed:
 
 static void btuart_release(struct pcmcia_device *link)
 {
-       btuart_info_t *info = link->priv;
+       struct btuart_info *info = link->priv;
 
        btuart_close(info);
 
index 292c38e8aa1760c000cdcce9ee6d223e9f819559..0527b29c3954be02db3693b4d338d0cbe59d7960 100644 (file)
@@ -165,6 +165,7 @@ static const struct usb_device_id blacklist_table[] = {
        { USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0930, 0x0227), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0cf3, 0x0036), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
index 2bd8fad172064af8f2211536fe8903e363ef33f1..78e10f0c65b28dc38d30336514b92614bc7e449c 100644 (file)
@@ -62,7 +62,7 @@ MODULE_LICENSE("GPL");
 /* ======================== Local structures ======================== */
 
 
-typedef struct dtl1_info_t {
+struct dtl1_info {
        struct pcmcia_device *p_dev;
 
        struct hci_dev *hdev;
@@ -78,7 +78,7 @@ typedef struct dtl1_info_t {
        unsigned long rx_state;
        unsigned long rx_count;
        struct sk_buff *rx_skb;
-} dtl1_info_t;
+};
 
 
 static int dtl1_config(struct pcmcia_device *link);
@@ -94,11 +94,11 @@ static int dtl1_config(struct pcmcia_device *link);
 #define RECV_WAIT_DATA  1
 
 
-typedef struct {
+struct nsh {
        u8 type;
        u8 zero;
        u16 len;
-} __packed nsh_t;      /* Nokia Specific Header */
+} __packed;    /* Nokia Specific Header */
 
 #define NSHL  4                                /* Nokia Specific Header Length */
 
@@ -126,7 +126,7 @@ static int dtl1_write(unsigned int iobase, int fifo_size, __u8 *buf, int len)
 }
 
 
-static void dtl1_write_wakeup(dtl1_info_t *info)
+static void dtl1_write_wakeup(struct dtl1_info *info)
 {
        if (!info) {
                BT_ERR("Unknown device");
@@ -176,7 +176,7 @@ static void dtl1_write_wakeup(dtl1_info_t *info)
 }
 
 
-static void dtl1_control(dtl1_info_t *info, struct sk_buff *skb)
+static void dtl1_control(struct dtl1_info *info, struct sk_buff *skb)
 {
        u8 flowmask = *(u8 *)skb->data;
        int i;
@@ -199,10 +199,10 @@ static void dtl1_control(dtl1_info_t *info, struct sk_buff *skb)
 }
 
 
-static void dtl1_receive(dtl1_info_t *info)
+static void dtl1_receive(struct dtl1_info *info)
 {
        unsigned int iobase;
-       nsh_t *nsh;
+       struct nsh *nsh;
        int boguscount = 0;
 
        if (!info) {
@@ -227,7 +227,7 @@ static void dtl1_receive(dtl1_info_t *info)
                }
 
                *skb_put(info->rx_skb, 1) = inb(iobase + UART_RX);
-               nsh = (nsh_t *)info->rx_skb->data;
+               nsh = (struct nsh *)info->rx_skb->data;
 
                info->rx_count--;
 
@@ -287,7 +287,7 @@ static void dtl1_receive(dtl1_info_t *info)
 
 static irqreturn_t dtl1_interrupt(int irq, void *dev_inst)
 {
-       dtl1_info_t *info = dev_inst;
+       struct dtl1_info *info = dev_inst;
        unsigned int iobase;
        unsigned char msr;
        int boguscount = 0;
@@ -365,7 +365,7 @@ static int dtl1_hci_open(struct hci_dev *hdev)
 
 static int dtl1_hci_flush(struct hci_dev *hdev)
 {
-       dtl1_info_t *info = hci_get_drvdata(hdev);
+       struct dtl1_info *info = hci_get_drvdata(hdev);
 
        /* Drop TX queue */
        skb_queue_purge(&(info->txq));
@@ -387,9 +387,9 @@ static int dtl1_hci_close(struct hci_dev *hdev)
 
 static int dtl1_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
 {
-       dtl1_info_t *info = hci_get_drvdata(hdev);
+       struct dtl1_info *info = hci_get_drvdata(hdev);
        struct sk_buff *s;
-       nsh_t nsh;
+       struct nsh nsh;
 
        switch (bt_cb(skb)->pkt_type) {
        case HCI_COMMAND_PKT:
@@ -436,7 +436,7 @@ static int dtl1_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
 /* ======================== Card services HCI interaction ======================== */
 
 
-static int dtl1_open(dtl1_info_t *info)
+static int dtl1_open(struct dtl1_info *info)
 {
        unsigned long flags;
        unsigned int iobase = info->p_dev->resource[0]->start;
@@ -505,7 +505,7 @@ static int dtl1_open(dtl1_info_t *info)
 }
 
 
-static int dtl1_close(dtl1_info_t *info)
+static int dtl1_close(struct dtl1_info *info)
 {
        unsigned long flags;
        unsigned int iobase = info->p_dev->resource[0]->start;
@@ -534,7 +534,7 @@ static int dtl1_close(dtl1_info_t *info)
 
 static int dtl1_probe(struct pcmcia_device *link)
 {
-       dtl1_info_t *info;
+       struct dtl1_info *info;
 
        /* Create new info device */
        info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
@@ -552,7 +552,7 @@ static int dtl1_probe(struct pcmcia_device *link)
 
 static void dtl1_detach(struct pcmcia_device *link)
 {
-       dtl1_info_t *info = link->priv;
+       struct dtl1_info *info = link->priv;
 
        dtl1_close(info);
        pcmcia_disable_device(link);
@@ -571,7 +571,7 @@ static int dtl1_confcheck(struct pcmcia_device *p_dev, void *priv_data)
 
 static int dtl1_config(struct pcmcia_device *link)
 {
-       dtl1_info_t *info = link->priv;
+       struct dtl1_info *info = link->priv;
        int ret;
 
        /* Look for a generic full-sized window */
index caacb422995dd4a69e18585275f32904a17bf708..a22838669b4ed227d447925ea45337f5efd9f72d 100644 (file)
@@ -237,7 +237,7 @@ static void h5_pkt_cull(struct h5 *h5)
                        break;
 
                to_remove--;
-               seq = (seq - 1) % 8;
+               seq = (seq - 1) & 0x07;
        }
 
        if (seq != h5->rx_ack)
index 3266f8ff931133e88ab419bc08ddad3a96bf1314..a60f26400705e11aae4ef6abcb8c840e94a33806 100644 (file)
@@ -586,6 +586,30 @@ static int arm_ccn_pmu_type_eq(u32 a, u32 b)
        return 0;
 }
 
+static void arm_ccn_pmu_event_destroy(struct perf_event *event)
+{
+       struct arm_ccn *ccn = pmu_to_arm_ccn(event->pmu);
+       struct hw_perf_event *hw = &event->hw;
+
+       if (hw->idx == CCN_IDX_PMU_CYCLE_COUNTER) {
+               clear_bit(CCN_IDX_PMU_CYCLE_COUNTER, ccn->dt.pmu_counters_mask);
+       } else {
+               struct arm_ccn_component *source =
+                               ccn->dt.pmu_counters[hw->idx].source;
+
+               if (CCN_CONFIG_TYPE(event->attr.config) == CCN_TYPE_XP &&
+                               CCN_CONFIG_EVENT(event->attr.config) ==
+                               CCN_EVENT_WATCHPOINT)
+                       clear_bit(hw->config_base, source->xp.dt_cmp_mask);
+               else
+                       clear_bit(hw->config_base, source->pmu_events_mask);
+               clear_bit(hw->idx, ccn->dt.pmu_counters_mask);
+       }
+
+       ccn->dt.pmu_counters[hw->idx].source = NULL;
+       ccn->dt.pmu_counters[hw->idx].event = NULL;
+}
+
 static int arm_ccn_pmu_event_init(struct perf_event *event)
 {
        struct arm_ccn *ccn;
@@ -599,6 +623,7 @@ static int arm_ccn_pmu_event_init(struct perf_event *event)
                return -ENOENT;
 
        ccn = pmu_to_arm_ccn(event->pmu);
+       event->destroy = arm_ccn_pmu_event_destroy;
 
        if (hw->sample_period) {
                dev_warn(ccn->dev, "Sampling not supported!\n");
@@ -662,7 +687,7 @@ static int arm_ccn_pmu_event_init(struct perf_event *event)
                }
                if (e->num_vcs && vc >= e->num_vcs) {
                        dev_warn(ccn->dev, "Invalid vc %d for node/XP %d!\n",
-                                       port, node_xp);
+                                       vc, node_xp);
                        return -EINVAL;
                }
                valid = 1;
@@ -731,30 +756,6 @@ static int arm_ccn_pmu_event_init(struct perf_event *event)
        return 0;
 }
 
-static void arm_ccn_pmu_event_free(struct perf_event *event)
-{
-       struct arm_ccn *ccn = pmu_to_arm_ccn(event->pmu);
-       struct hw_perf_event *hw = &event->hw;
-
-       if (hw->idx == CCN_IDX_PMU_CYCLE_COUNTER) {
-               clear_bit(CCN_IDX_PMU_CYCLE_COUNTER, ccn->dt.pmu_counters_mask);
-       } else {
-               struct arm_ccn_component *source =
-                               ccn->dt.pmu_counters[hw->idx].source;
-
-               if (CCN_CONFIG_TYPE(event->attr.config) == CCN_TYPE_XP &&
-                               CCN_CONFIG_EVENT(event->attr.config) ==
-                               CCN_EVENT_WATCHPOINT)
-                       clear_bit(hw->config_base, source->xp.dt_cmp_mask);
-               else
-                       clear_bit(hw->config_base, source->pmu_events_mask);
-               clear_bit(hw->idx, ccn->dt.pmu_counters_mask);
-       }
-
-       ccn->dt.pmu_counters[hw->idx].source = NULL;
-       ccn->dt.pmu_counters[hw->idx].event = NULL;
-}
-
 static u64 arm_ccn_pmu_read_counter(struct arm_ccn *ccn, int idx)
 {
        u64 res;
@@ -1027,8 +1028,6 @@ static int arm_ccn_pmu_event_add(struct perf_event *event, int flags)
 static void arm_ccn_pmu_event_del(struct perf_event *event, int flags)
 {
        arm_ccn_pmu_event_stop(event, PERF_EF_UPDATE);
-
-       arm_ccn_pmu_event_free(event);
 }
 
 static void arm_ccn_pmu_event_read(struct perf_event *event)
index 0027137daa561500ea8089423b3c22eb34f1bb84..2e3139eda93b687568aeda1698c5022eb9144c64 100644 (file)
@@ -116,6 +116,7 @@ static int probe_common(struct virtio_device *vdev)
                .cleanup = virtio_cleanup,
                .priv = (unsigned long)vi,
                .name = vi->name,
+               .quality = 1000,
        };
        vdev->priv = vi;
 
index c5eac949760de99ab8345fa1933657278afe7092..0668b389c5165cae8d02e4bedb270b32b8372bde 100644 (file)
@@ -660,6 +660,7 @@ static const struct x86_cpu_id intel_pstate_cpu_ids[] = {
        ICPU(0x3f, core_params),
        ICPU(0x45, core_params),
        ICPU(0x46, core_params),
+       ICPU(0x4c, byt_params),
        ICPU(0x4f, core_params),
        ICPU(0x56, core_params),
        {}
@@ -688,7 +689,7 @@ static int intel_pstate_init_cpu(unsigned int cpunum)
 
        add_timer_on(&cpu->timer, cpunum);
 
-       pr_info("Intel pstate controlling: cpu %d\n", cpunum);
+       pr_debug("Intel pstate controlling: cpu %d\n", cpunum);
 
        return 0;
 }
@@ -707,10 +708,6 @@ static unsigned int intel_pstate_get(unsigned int cpu_num)
 
 static int intel_pstate_set_policy(struct cpufreq_policy *policy)
 {
-       struct cpudata *cpu;
-
-       cpu = all_cpu_data[policy->cpu];
-
        if (!policy->cpuinfo.max_freq)
                return -ENODEV;
 
index 9a68225a757e44edd2554f9672197ee64363a5ad..3f9791f07b8ea05f745a2bcbce6b738379443087 100644 (file)
@@ -501,7 +501,7 @@ static int check_mem_type(void __iomem *dmc_reg)
        return val >> 8;
 }
 
-static int __init s5pv210_cpu_init(struct cpufreq_policy *policy)
+static int s5pv210_cpu_init(struct cpufreq_policy *policy)
 {
        unsigned long mem_type;
        int ret;
index 344d79fa34078166694d1301b4c93e939a94e76b..ef94c3b81f18048c6feee67368d2fd24da416424 100644 (file)
@@ -138,25 +138,18 @@ static int bl_enter_powerdown(struct cpuidle_device *dev,
        return idx;
 }
 
-static int __init bl_idle_driver_init(struct cpuidle_driver *drv, int cpu_id)
+static int __init bl_idle_driver_init(struct cpuidle_driver *drv, int part_id)
 {
-       struct cpuinfo_arm *cpu_info;
        struct cpumask *cpumask;
-       unsigned long cpuid;
        int cpu;
 
        cpumask = kzalloc(cpumask_size(), GFP_KERNEL);
        if (!cpumask)
                return -ENOMEM;
 
-       for_each_possible_cpu(cpu) {
-               cpu_info = &per_cpu(cpu_data, cpu);
-               cpuid = is_smp() ? cpu_info->cpuid : read_cpuid_id();
-
-               /* read cpu id part number */
-               if ((cpuid & 0xFFF0) == cpu_id)
+       for_each_possible_cpu(cpu)
+               if (smp_cpuid_part(cpu) == part_id)
                        cpumask_set_cpu(cpu, cpumask);
-       }
 
        drv->cpumask = cpumask;
 
index 4222cb2aa96aa18e66a75f76d0d56b3feb346982..7bb9d65d9a2c9c99f12314c537fa8cf00c0929ef 100644 (file)
@@ -29,7 +29,7 @@
 EXPORT_TRACEPOINT_SYMBOL(fence_annotate_wait_on);
 EXPORT_TRACEPOINT_SYMBOL(fence_emit);
 
-/**
+/*
  * fence context counter: each execution context should have its own
  * fence context, this allows checking if fences belong to the same
  * context or not. One device can have multiple separate contexts,
index f8665f9c3e0332f1a0d3eda12bd9d5edf97e9c65..fd89ca982748ed9cac8ff11e0b0c4bce59110c2c 100644 (file)
@@ -253,12 +253,12 @@ config EDAC_I7300
          Clarksboro MCH (Intel 7300 chipset).
 
 config EDAC_SBRIDGE
-       tristate "Intel Sandy-Bridge Integrated MC"
+       tristate "Intel Sandy-Bridge/Ivy-Bridge/Haswell Integrated MC"
        depends on EDAC_MM_EDAC && PCI && X86_64 && X86_MCE_INTEL
        depends on PCI_MMCONFIG
        help
          Support for error detection and correction the Intel
-         Sandy Bridge Integrated Memory Controller.
+         Sandy Bridge, Ivy Bridge and Haswell Integrated Memory Controllers.
 
 config EDAC_MPC85XX
        tristate "Freescale MPC83xx / MPC85xx"
index 01fae8289cf05fe5f9f95bd3da13628f471aa260..a6cd36100663278dccae072e724bcc0c71c51794 100644 (file)
@@ -108,7 +108,9 @@ static const char * const mem_types[] = {
        [MEM_RDDR2] = "Registered-DDR2",
        [MEM_XDR] = "XDR",
        [MEM_DDR3] = "Unbuffered-DDR3",
-       [MEM_RDDR3] = "Registered-DDR3"
+       [MEM_RDDR3] = "Registered-DDR3",
+       [MEM_DDR4] = "Unbuffered-DDR4",
+       [MEM_RDDR4] = "Registered-DDR4"
 };
 
 static const char * const dev_types[] = {
index deea0dc9999bf1bb54d58fd2d43d4c98036d690e..0034c48444280e7c40d21fd0f94d8faf4a9b7df2 100644 (file)
@@ -99,6 +99,7 @@ static const u32 ibridge_dram_rule[] = {
 #define DRAM_ATTR(reg)         GET_BITFIELD(reg, 2,  3)
 #define INTERLEAVE_MODE(reg)   GET_BITFIELD(reg, 1,  1)
 #define DRAM_RULE_ENABLE(reg)  GET_BITFIELD(reg, 0,  0)
+#define A7MODE(reg)            GET_BITFIELD(reg, 26, 26)
 
 static char *get_dram_attr(u32 reg)
 {
@@ -164,6 +165,8 @@ static inline int sad_pkg(const struct interleave_pkg *table, u32 reg,
 
 #define TOLM           0x80
 #define        TOHM            0x84
+#define HASWELL_TOHM_0 0xd4
+#define HASWELL_TOHM_1 0xd8
 
 #define GET_TOLM(reg)          ((GET_BITFIELD(reg, 0,  3) << 28) | 0x3ffffff)
 #define GET_TOHM(reg)          ((GET_BITFIELD(reg, 0, 20) << 25) | 0x3ffffff)
@@ -176,8 +179,6 @@ static inline int sad_pkg(const struct interleave_pkg *table, u32 reg,
 
 #define SAD_CONTROL    0xf4
 
-#define NODE_ID(reg)           GET_BITFIELD(reg, 0, 2)
-
 /* Device 14 function 0 */
 
 static const u32 tad_dram_rule[] = {
@@ -235,7 +236,6 @@ static const u32 rir_way_limit[] = {
 
 #define IS_RIR_VALID(reg)      GET_BITFIELD(reg, 31, 31)
 #define RIR_WAY(reg)           GET_BITFIELD(reg, 28, 29)
-#define RIR_LIMIT(reg)         ((GET_BITFIELD(reg,  1, 10) << 29)| 0x1fffffff)
 
 #define MAX_RIR_WAY    8
 
@@ -279,8 +279,6 @@ static const u32 correrrthrsld[] = {
 
 #define IB_RANK_CFG_A          0x0320
 
-#define IS_RDIMM_ENABLED(reg)          GET_BITFIELD(reg, 11, 11)
-
 /*
  * sbridge structs
  */
@@ -291,6 +289,7 @@ static const u32 correrrthrsld[] = {
 enum type {
        SANDY_BRIDGE,
        IVY_BRIDGE,
+       HASWELL,
 };
 
 struct sbridge_pvt;
@@ -300,11 +299,15 @@ struct sbridge_info {
        u32             rankcfgr;
        u64             (*get_tolm)(struct sbridge_pvt *pvt);
        u64             (*get_tohm)(struct sbridge_pvt *pvt);
+       u64             (*rir_limit)(u32 reg);
        const u32       *dram_rule;
        const u32       *interleave_list;
        const struct interleave_pkg *interleave_pkg;
        u8              max_sad;
        u8              max_interleave;
+       u8              (*get_node_id)(struct sbridge_pvt *pvt);
+       enum mem_type   (*get_memory_type)(struct sbridge_pvt *pvt);
+       struct pci_dev  *pci_vtd;
 };
 
 struct sbridge_channel {
@@ -313,9 +316,7 @@ struct sbridge_channel {
 };
 
 struct pci_id_descr {
-       int                     dev;
-       int                     func;
-       int                     dev_id;
+       int                     dev_id;
        int                     optional;
 };
 
@@ -338,6 +339,7 @@ struct sbridge_pvt {
        struct pci_dev          *pci_sad0, *pci_sad1;
        struct pci_dev          *pci_ha0, *pci_ha1;
        struct pci_dev          *pci_br0, *pci_br1;
+       struct pci_dev          *pci_ha1_ta;
        struct pci_dev          *pci_tad[NUM_CHANNELS];
 
        struct sbridge_dev      *sbridge_dev;
@@ -362,31 +364,29 @@ struct sbridge_pvt {
        u64                     tolm, tohm;
 };
 
-#define PCI_DESCR(device, function, device_id, opt)    \
-       .dev = (device),                                \
-       .func = (function),                             \
-       .dev_id = (device_id),                          \
+#define PCI_DESCR(device_id, opt)      \
+       .dev_id = (device_id),          \
        .optional = opt
 
 static const struct pci_id_descr pci_dev_descr_sbridge[] = {
                /* Processor Home Agent */
-       { PCI_DESCR(14, 0, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_HA0, 0)      },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_HA0, 0)     },
 
                /* Memory controller */
-       { PCI_DESCR(15, 0, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA, 0)       },
-       { PCI_DESCR(15, 1, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_RAS, 0)      },
-       { PCI_DESCR(15, 2, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD0, 0)     },
-       { PCI_DESCR(15, 3, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD1, 0)     },
-       { PCI_DESCR(15, 4, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD2, 0)     },
-       { PCI_DESCR(15, 5, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD3, 0)     },
-       { PCI_DESCR(17, 0, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_DDRIO, 1)    },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA, 0)      },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_RAS, 0)     },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD0, 0)    },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD1, 0)    },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD2, 0)    },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD3, 0)    },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_DDRIO, 1)   },
 
                /* System Address Decoder */
-       { PCI_DESCR(12, 6, PCI_DEVICE_ID_INTEL_SBRIDGE_SAD0, 0)         },
-       { PCI_DESCR(12, 7, PCI_DEVICE_ID_INTEL_SBRIDGE_SAD1, 0)         },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_SAD0, 0)        },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_SAD1, 0)        },
 
                /* Broadcast Registers */
-       { PCI_DESCR(13, 6, PCI_DEVICE_ID_INTEL_SBRIDGE_BR, 0)           },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_SBRIDGE_BR, 0)          },
 };
 
 #define PCI_ID_TABLE_ENTRY(A) { .descr=A, .n_devs = ARRAY_SIZE(A) }
@@ -423,34 +423,34 @@ static const struct pci_id_table pci_dev_descr_sbridge_table[] = {
 
 static const struct pci_id_descr pci_dev_descr_ibridge[] = {
                /* Processor Home Agent */
-       { PCI_DESCR(14, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0, 0)      },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0, 0)             },
 
                /* Memory controller */
-       { PCI_DESCR(15, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA, 0)   },
-       { PCI_DESCR(15, 1, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_RAS, 0)  },
-       { PCI_DESCR(15, 2, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD0, 0) },
-       { PCI_DESCR(15, 3, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD1, 0) },
-       { PCI_DESCR(15, 4, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD2, 0) },
-       { PCI_DESCR(15, 5, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD3, 0) },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA, 0)          },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_RAS, 0)         },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD0, 0)        },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD1, 0)        },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD2, 0)        },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD3, 0)        },
 
                /* System Address Decoder */
-       { PCI_DESCR(22, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_SAD, 0)          },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_SAD, 0)                 },
 
                /* Broadcast Registers */
-       { PCI_DESCR(22, 1, PCI_DEVICE_ID_INTEL_IBRIDGE_BR0, 1)          },
-       { PCI_DESCR(22, 2, PCI_DEVICE_ID_INTEL_IBRIDGE_BR1, 0)          },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_BR0, 1)                 },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_BR1, 0)                 },
 
                /* Optional, mode 2HA */
-       { PCI_DESCR(28, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1, 1)      },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1, 1)             },
 #if 0
-       { PCI_DESCR(29, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TA, 1)   },
-       { PCI_DESCR(29, 1, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_RAS, 1)  },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TA, 1)  },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_RAS, 1) },
 #endif
-       { PCI_DESCR(29, 2, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD0, 1) },
-       { PCI_DESCR(29, 3, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD1, 1) },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD0, 1)        },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD1, 1)        },
 
-       { PCI_DESCR(17, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_1HA_DDRIO0, 1) },
-       { PCI_DESCR(17, 4, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_2HA_DDRIO0, 1) },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_1HA_DDRIO0, 1)      },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_2HA_DDRIO0, 1)      },
 };
 
 static const struct pci_id_table pci_dev_descr_ibridge_table[] = {
@@ -458,12 +458,80 @@ static const struct pci_id_table pci_dev_descr_ibridge_table[] = {
        {0,}                    /* 0 terminated list. */
 };
 
+/* Haswell support */
+/* EN processor:
+ *     - 1 IMC
+ *     - 3 DDR3 channels, 2 DPC per channel
+ * EP processor:
+ *     - 1 or 2 IMC
+ *     - 4 DDR4 channels, 3 DPC per channel
+ * EP 4S processor:
+ *     - 2 IMC
+ *     - 4 DDR4 channels, 3 DPC per channel
+ * EX processor:
+ *     - 2 IMC
+ *     - each IMC interfaces with a SMI 2 channel
+ *     - each SMI channel interfaces with a scalable memory buffer
+ *     - each scalable memory buffer supports 4 DDR3/DDR4 channels, 3 DPC
+ */
+#define HASWELL_DDRCRCLKCONTROLS 0xa10
+#define HASWELL_HASYSDEFEATURE2 0x84
+#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_VTD_MISC 0x2f28
+#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0    0x2fa0
+#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1    0x2f60
+#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TA 0x2fa8
+#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_THERMAL 0x2f71
+#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TA 0x2f68
+#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_THERMAL 0x2f79
+#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_CBO_SAD0 0x2ffc
+#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_CBO_SAD1 0x2ffd
+#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD0 0x2faa
+#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD1 0x2fab
+#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD2 0x2fac
+#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD3 0x2fad
+#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD0 0x2f6a
+#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD1 0x2f6b
+#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD2 0x2f6c
+#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD3 0x2f6d
+#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO0 0x2fbd
+static const struct pci_id_descr pci_dev_descr_haswell[] = {
+       /* first item must be the HA */
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0, 0)             },
+
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_CBO_SAD0, 0)        },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_CBO_SAD1, 0)        },
+
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1, 1)             },
+
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TA, 0)          },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_THERMAL, 0)     },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD0, 0)        },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD1, 0)        },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD2, 1)        },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD3, 1)        },
+
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO0, 1)          },
+
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TA, 1)          },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_THERMAL, 1)     },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD0, 1)        },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD1, 1)        },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD2, 1)        },
+       { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD3, 1)        },
+};
+
+static const struct pci_id_table pci_dev_descr_haswell_table[] = {
+       PCI_ID_TABLE_ENTRY(pci_dev_descr_haswell),
+       {0,}                    /* 0 terminated list. */
+};
+
 /*
  *     pci_device_id   table for which devices we are looking for
  */
 static const struct pci_device_id sbridge_pci_tbl[] = {
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA)},
        {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA)},
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0)},
        {0,}                    /* 0 terminated list. */
 };
 
@@ -472,13 +540,17 @@ static const struct pci_device_id sbridge_pci_tbl[] = {
                        Ancillary status routines
  ****************************************************************************/
 
-static inline int numrank(u32 mtr)
+static inline int numrank(enum type type, u32 mtr)
 {
        int ranks = (1 << RANK_CNT_BITS(mtr));
+       int max = 4;
 
-       if (ranks > 4) {
-               edac_dbg(0, "Invalid number of ranks: %d (max = 4) raw value = %x (%04x)\n",
-                        ranks, (unsigned int)RANK_CNT_BITS(mtr), mtr);
+       if (type == HASWELL)
+               max = 8;
+
+       if (ranks > max) {
+               edac_dbg(0, "Invalid number of ranks: %d (max = %i) raw value = %x (%04x)\n",
+                        ranks, max, (unsigned int)RANK_CNT_BITS(mtr), mtr);
                return -EINVAL;
        }
 
@@ -588,10 +660,107 @@ static u64 ibridge_get_tohm(struct sbridge_pvt *pvt)
        return GET_TOHM(reg);
 }
 
+static u64 rir_limit(u32 reg)
+{
+       return ((u64)GET_BITFIELD(reg,  1, 10) << 29) | 0x1fffffff;
+}
+
+static enum mem_type get_memory_type(struct sbridge_pvt *pvt)
+{
+       u32 reg;
+       enum mem_type mtype;
+
+       if (pvt->pci_ddrio) {
+               pci_read_config_dword(pvt->pci_ddrio, pvt->info.rankcfgr,
+                                     &reg);
+               if (GET_BITFIELD(reg, 11, 11))
+                       /* FIXME: Can also be LRDIMM */
+                       mtype = MEM_RDDR3;
+               else
+                       mtype = MEM_DDR3;
+       } else
+               mtype = MEM_UNKNOWN;
+
+       return mtype;
+}
+
+static enum mem_type haswell_get_memory_type(struct sbridge_pvt *pvt)
+{
+       u32 reg;
+       bool registered = false;
+       enum mem_type mtype = MEM_UNKNOWN;
+
+       if (!pvt->pci_ddrio)
+               goto out;
+
+       pci_read_config_dword(pvt->pci_ddrio,
+                             HASWELL_DDRCRCLKCONTROLS, &reg);
+       /* Is_Rdimm */
+       if (GET_BITFIELD(reg, 16, 16))
+               registered = true;
+
+       pci_read_config_dword(pvt->pci_ta, MCMTR, &reg);
+       if (GET_BITFIELD(reg, 14, 14)) {
+               if (registered)
+                       mtype = MEM_RDDR4;
+               else
+                       mtype = MEM_DDR4;
+       } else {
+               if (registered)
+                       mtype = MEM_RDDR3;
+               else
+                       mtype = MEM_DDR3;
+       }
+
+out:
+       return mtype;
+}
+
+static u8 get_node_id(struct sbridge_pvt *pvt)
+{
+       u32 reg;
+       pci_read_config_dword(pvt->pci_br0, SAD_CONTROL, &reg);
+       return GET_BITFIELD(reg, 0, 2);
+}
+
+static u8 haswell_get_node_id(struct sbridge_pvt *pvt)
+{
+       u32 reg;
+
+       pci_read_config_dword(pvt->pci_sad1, SAD_CONTROL, &reg);
+       return GET_BITFIELD(reg, 0, 3);
+}
+
+static u64 haswell_get_tolm(struct sbridge_pvt *pvt)
+{
+       u32 reg;
+
+       pci_read_config_dword(pvt->info.pci_vtd, TOLM, &reg);
+       return (GET_BITFIELD(reg, 26, 31) << 26) | 0x1ffffff;
+}
+
+static u64 haswell_get_tohm(struct sbridge_pvt *pvt)
+{
+       u64 rc;
+       u32 reg;
+
+       pci_read_config_dword(pvt->info.pci_vtd, HASWELL_TOHM_0, &reg);
+       rc = GET_BITFIELD(reg, 26, 31);
+       pci_read_config_dword(pvt->info.pci_vtd, HASWELL_TOHM_1, &reg);
+       rc = ((reg << 6) | rc) << 26;
+
+       return rc | 0x1ffffff;
+}
+
+static u64 haswell_rir_limit(u32 reg)
+{
+       return (((u64)GET_BITFIELD(reg,  1, 11) + 1) << 29) - 1;
+}
+
 static inline u8 sad_pkg_socket(u8 pkg)
 {
        /* on Ivy Bridge, nodeID is SASS, where A is HA and S is node id */
-       return (pkg >> 3) | (pkg & 0x3);
+       return ((pkg >> 3) << 2) | (pkg & 0x3);
 }
 
 static inline u8 sad_pkg_ha(u8 pkg)
@@ -602,44 +771,43 @@ static inline u8 sad_pkg_ha(u8 pkg)
 /****************************************************************************
                        Memory check routines
  ****************************************************************************/
-static struct pci_dev *get_pdev_slot_func(u8 bus, unsigned slot,
-                                         unsigned func)
+static struct pci_dev *get_pdev_same_bus(u8 bus, u32 id)
 {
-       struct sbridge_dev *sbridge_dev = get_sbridge_dev(bus);
-       int i;
-
-       if (!sbridge_dev)
-               return NULL;
-
-       for (i = 0; i < sbridge_dev->n_devs; i++) {
-               if (!sbridge_dev->pdev[i])
-                       continue;
+       struct pci_dev *pdev = NULL;
 
-               if (PCI_SLOT(sbridge_dev->pdev[i]->devfn) == slot &&
-                   PCI_FUNC(sbridge_dev->pdev[i]->devfn) == func) {
-                       edac_dbg(1, "Associated %02x.%02x.%d with %p\n",
-                                bus, slot, func, sbridge_dev->pdev[i]);
-                       return sbridge_dev->pdev[i];
-               }
-       }
+       do {
+               pdev = pci_get_device(PCI_VENDOR_ID_INTEL, id, pdev);
+               if (pdev && pdev->bus->number == bus)
+                       break;
+       } while (pdev);
 
-       return NULL;
+       return pdev;
 }
 
 /**
  * check_if_ecc_is_active() - Checks if ECC is active
- * bus:                Device bus
+ * @bus:       Device bus
+ * @type:      Memory controller type
+ * returns: 0 in case ECC is active, -ENODEV if it can't be determined or
+ *         disabled
  */
-static int check_if_ecc_is_active(const u8 bus)
+static int check_if_ecc_is_active(const u8 bus, enum type type)
 {
        struct pci_dev *pdev = NULL;
-       u32 mcmtr;
+       u32 mcmtr, id;
+
+       if (type == IVY_BRIDGE)
+               id = PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA;
+       else if (type == HASWELL)
+               id = PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TA;
+       else
+               id = PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA;
 
-       pdev = get_pdev_slot_func(bus, 15, 0);
+       pdev = get_pdev_same_bus(bus, id);
        if (!pdev) {
                sbridge_printk(KERN_ERR, "Couldn't find PCI device "
-                                       "%2x.%02d.%d!!!\n",
-                                       bus, 15, 0);
+                                       "%04x:%04x! on bus %02d\n",
+                                       PCI_VENDOR_ID_INTEL, id, bus);
                return -ENODEV;
        }
 
@@ -661,11 +829,14 @@ static int get_dimm_config(struct mem_ctl_info *mci)
        enum edac_type mode;
        enum mem_type mtype;
 
-       pci_read_config_dword(pvt->pci_br0, SAD_TARGET, &reg);
+       if (pvt->info.type == HASWELL)
+               pci_read_config_dword(pvt->pci_sad1, SAD_TARGET, &reg);
+       else
+               pci_read_config_dword(pvt->pci_br0, SAD_TARGET, &reg);
+
        pvt->sbridge_dev->source_id = SOURCE_ID(reg);
 
-       pci_read_config_dword(pvt->pci_br0, SAD_CONTROL, &reg);
-       pvt->sbridge_dev->node_id = NODE_ID(reg);
+       pvt->sbridge_dev->node_id = pvt->info.get_node_id(pvt);
        edac_dbg(0, "mc#%d: Node ID: %d, source ID: %d\n",
                 pvt->sbridge_dev->mc,
                 pvt->sbridge_dev->node_id,
@@ -698,24 +869,18 @@ static int get_dimm_config(struct mem_ctl_info *mci)
                pvt->is_close_pg = false;
        }
 
-       if (pvt->pci_ddrio) {
-               pci_read_config_dword(pvt->pci_ddrio, pvt->info.rankcfgr,
-                                     &reg);
-               if (IS_RDIMM_ENABLED(reg)) {
-                       /* FIXME: Can also be LRDIMM */
-                       edac_dbg(0, "Memory is registered\n");
-                       mtype = MEM_RDDR3;
-               } else {
-                       edac_dbg(0, "Memory is unregistered\n");
-                       mtype = MEM_DDR3;
-               }
-       } else {
+       mtype = pvt->info.get_memory_type(pvt);
+       if (mtype == MEM_RDDR3 || mtype == MEM_RDDR4)
+               edac_dbg(0, "Memory is registered\n");
+       else if (mtype == MEM_UNKNOWN)
                edac_dbg(0, "Cannot determine memory type\n");
-               mtype = MEM_UNKNOWN;
-       }
+       else
+               edac_dbg(0, "Memory is unregistered\n");
 
-       /* On all supported DDR3 DIMM types, there are 8 banks available */
-       banks = 8;
+       if (mtype == MEM_DDR4 || MEM_RDDR4)
+               banks = 16;
+       else
+               banks = 8;
 
        for (i = 0; i < NUM_CHANNELS; i++) {
                u32 mtr;
@@ -729,11 +894,10 @@ static int get_dimm_config(struct mem_ctl_info *mci)
                        if (IS_DIMM_PRESENT(mtr)) {
                                pvt->channel[i].dimms++;
 
-                               ranks = numrank(mtr);
+                               ranks = numrank(pvt->info.type, mtr);
                                rows = numrow(mtr);
                                cols = numcol(mtr);
 
-                               /* DDR3 has 8 I/O banks */
                                size = ((u64)rows * cols * banks * ranks) >> (20 - 3);
                                npages = MiB_TO_PAGES(size);
 
@@ -744,7 +908,17 @@ static int get_dimm_config(struct mem_ctl_info *mci)
 
                                dimm->nr_pages = npages;
                                dimm->grain = 32;
-                               dimm->dtype = (banks == 8) ? DEV_X8 : DEV_X4;
+                               switch (banks) {
+                               case 16:
+                                       dimm->dtype = DEV_X16;
+                                       break;
+                               case 8:
+                                       dimm->dtype = DEV_X8;
+                                       break;
+                               case 4:
+                                       dimm->dtype = DEV_X4;
+                                       break;
+                               }
                                dimm->mtype = mtype;
                                dimm->edac_mode = mode;
                                snprintf(dimm->label, sizeof(dimm->label),
@@ -887,7 +1061,7 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
                        if (!IS_RIR_VALID(reg))
                                continue;
 
-                       tmp_mb = RIR_LIMIT(reg) >> 20;
+                       tmp_mb = pvt->info.rir_limit(reg) >> 20;
                        rir_way = 1 << RIR_WAY(reg);
                        mb = div_u64_rem(tmp_mb, 1000, &kb);
                        edac_dbg(0, "CH#%d RIR#%d, limit: %u.%03u GB (0x%016Lx), way: %d, reg=0x%08x\n",
@@ -936,11 +1110,11 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
        struct mem_ctl_info     *new_mci;
        struct sbridge_pvt *pvt = mci->pvt_info;
        struct pci_dev          *pci_ha;
-       int                     n_rir, n_sads, n_tads, sad_way, sck_xch;
+       int                     n_rir, n_sads, n_tads, sad_way, sck_xch;
        int                     sad_interl, idx, base_ch;
-       int                     interleave_mode;
+       int                     interleave_mode, shiftup = 0;
        unsigned                sad_interleave[pvt->info.max_interleave];
-       u32                     reg;
+       u32                     reg, dram_rule;
        u8                      ch_way, sck_way, pkg, sad_ha = 0;
        u32                     tad_offset;
        u32                     rir_way;
@@ -987,8 +1161,9 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
                sprintf(msg, "Can't discover the memory socket");
                return -EINVAL;
        }
-       *area_type = get_dram_attr(reg);
-       interleave_mode = INTERLEAVE_MODE(reg);
+       dram_rule = reg;
+       *area_type = get_dram_attr(dram_rule);
+       interleave_mode = INTERLEAVE_MODE(dram_rule);
 
        pci_read_config_dword(pvt->pci_sad0, pvt->info.interleave_list[n_sads],
                              &reg);
@@ -1033,6 +1208,36 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
                *socket = sad_interleave[idx];
                edac_dbg(0, "SAD interleave index: %d (wayness %d) = CPU socket %d\n",
                         idx, sad_way, *socket);
+       } else if (pvt->info.type == HASWELL) {
+               int bits, a7mode = A7MODE(dram_rule);
+
+               if (a7mode) {
+                       /* A7 mode swaps P9 with P6 */
+                       bits = GET_BITFIELD(addr, 7, 8) << 1;
+                       bits |= GET_BITFIELD(addr, 9, 9);
+               } else
+                       bits = GET_BITFIELD(addr, 7, 9);
+
+               if (interleave_mode) {
+                       /* interleave mode will XOR {8,7,6} with {18,17,16} */
+                       idx = GET_BITFIELD(addr, 16, 18);
+                       idx ^= bits;
+               } else
+                       idx = bits;
+
+               pkg = sad_pkg(pvt->info.interleave_pkg, reg, idx);
+               *socket = sad_pkg_socket(pkg);
+               sad_ha = sad_pkg_ha(pkg);
+
+               if (a7mode) {
+                       /* MCChanShiftUpEnable */
+                       pci_read_config_dword(pvt->pci_ha0,
+                                             HASWELL_HASYSDEFEATURE2, &reg);
+                       shiftup = GET_BITFIELD(reg, 22, 22);
+               }
+
+               edac_dbg(0, "SAD interleave package: %d = CPU socket %d, HA %i, shiftup: %i\n",
+                        idx, *socket, sad_ha, shiftup);
        } else {
                /* Ivy Bridge's SAD mode doesn't support XOR interleave mode */
                idx = (addr >> 6) & 7;
@@ -1090,7 +1295,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
        if (ch_way == 3)
                idx = addr >> 6;
        else
-               idx = addr >> (6 + sck_way);
+               idx = (addr >> (6 + sck_way + shiftup)) & 0x3;
        idx = idx % ch_way;
 
        /*
@@ -1181,7 +1386,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
                if (!IS_RIR_VALID(reg))
                        continue;
 
-               limit = RIR_LIMIT(reg);
+               limit = pvt->info.rir_limit(reg);
                mb = div_u64_rem(limit >> 20, 1000, &kb);
                edac_dbg(0, "RIR#%d, limit: %u.%03u GB (0x%016Lx), way: %d\n",
                         n_rir,
@@ -1197,6 +1402,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
                return -EINVAL;
        }
        rir_way = RIR_WAY(reg);
+
        if (pvt->is_close_pg)
                idx = (ch_addr >> 6);
        else
@@ -1259,13 +1465,11 @@ static int sbridge_get_onedevice(struct pci_dev **prev,
 {
        struct sbridge_dev *sbridge_dev;
        const struct pci_id_descr *dev_descr = &table->descr[devno];
-
        struct pci_dev *pdev = NULL;
        u8 bus = 0;
 
        sbridge_printk(KERN_DEBUG,
-               "Seeking for: dev %02x.%d PCI ID %04x:%04x\n",
-               dev_descr->dev, dev_descr->func,
+               "Seeking for: PCI ID %04x:%04x\n",
                PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
 
        pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
@@ -1280,12 +1484,12 @@ static int sbridge_get_onedevice(struct pci_dev **prev,
                if (dev_descr->optional)
                        return 0;
 
+               /* if the HA wasn't found */
                if (devno == 0)
                        return -ENODEV;
 
                sbridge_printk(KERN_INFO,
-                       "Device not found: dev %02x.%d PCI ID %04x:%04x\n",
-                       dev_descr->dev, dev_descr->func,
+                       "Device not found: %04x:%04x\n",
                        PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
 
                /* End of list, leave */
@@ -1305,9 +1509,7 @@ static int sbridge_get_onedevice(struct pci_dev **prev,
 
        if (sbridge_dev->pdev[devno]) {
                sbridge_printk(KERN_ERR,
-                       "Duplicated device for "
-                       "dev %02x:%d.%d PCI ID %04x:%04x\n",
-                       bus, dev_descr->dev, dev_descr->func,
+                       "Duplicated device for %04x:%04x\n",
                        PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
                pci_dev_put(pdev);
                return -ENODEV;
@@ -1315,30 +1517,15 @@ static int sbridge_get_onedevice(struct pci_dev **prev,
 
        sbridge_dev->pdev[devno] = pdev;
 
-       /* Sanity check */
-       if (unlikely(PCI_SLOT(pdev->devfn) != dev_descr->dev ||
-                       PCI_FUNC(pdev->devfn) != dev_descr->func)) {
-               sbridge_printk(KERN_ERR,
-                       "Device PCI ID %04x:%04x "
-                       "has dev %02x:%d.%d instead of dev %02x:%02x.%d\n",
-                       PCI_VENDOR_ID_INTEL, dev_descr->dev_id,
-                       bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
-                       bus, dev_descr->dev, dev_descr->func);
-               return -ENODEV;
-       }
-
        /* Be sure that the device is enabled */
        if (unlikely(pci_enable_device(pdev) < 0)) {
                sbridge_printk(KERN_ERR,
-                       "Couldn't enable "
-                       "dev %02x:%d.%d PCI ID %04x:%04x\n",
-                       bus, dev_descr->dev, dev_descr->func,
+                       "Couldn't enable %04x:%04x\n",
                        PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
                return -ENODEV;
        }
 
-       edac_dbg(0, "Detected dev %02x:%d.%d PCI ID %04x:%04x\n",
-                bus, dev_descr->dev, dev_descr->func,
+       edac_dbg(0, "Detected %04x:%04x\n",
                 PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
 
        /*
@@ -1355,10 +1542,9 @@ static int sbridge_get_onedevice(struct pci_dev **prev,
 
 /*
  * sbridge_get_all_devices - Find and perform 'get' operation on the MCH's
- *                          device/functions we want to reference for this driver.
- *                          Need to 'get' device 16 func 1 and func 2.
+ *                          devices we want to reference for this driver.
  * @num_mc: pointer to the memory controllers count, to be incremented in case
- *         of success.
+ *         of success.
  * @table: model specific table
  *
  * returns 0 in case of success or error code
@@ -1396,79 +1582,51 @@ static int sbridge_mci_bind_devs(struct mem_ctl_info *mci,
 {
        struct sbridge_pvt *pvt = mci->pvt_info;
        struct pci_dev *pdev;
-       int i, func, slot;
+       int i;
 
        for (i = 0; i < sbridge_dev->n_devs; i++) {
                pdev = sbridge_dev->pdev[i];
                if (!pdev)
                        continue;
-               slot = PCI_SLOT(pdev->devfn);
-               func = PCI_FUNC(pdev->devfn);
-               switch (slot) {
-               case 12:
-                       switch (func) {
-                       case 6:
-                               pvt->pci_sad0 = pdev;
-                               break;
-                       case 7:
-                               pvt->pci_sad1 = pdev;
-                               break;
-                       default:
-                               goto error;
-                       }
+
+               switch (pdev->device) {
+               case PCI_DEVICE_ID_INTEL_SBRIDGE_SAD0:
+                       pvt->pci_sad0 = pdev;
                        break;
-               case 13:
-                       switch (func) {
-                       case 6:
-                               pvt->pci_br0 = pdev;
-                               break;
-                       default:
-                               goto error;
-                       }
+               case PCI_DEVICE_ID_INTEL_SBRIDGE_SAD1:
+                       pvt->pci_sad1 = pdev;
                        break;
-               case 14:
-                       switch (func) {
-                       case 0:
-                               pvt->pci_ha0 = pdev;
-                               break;
-                       default:
-                               goto error;
-                       }
+               case PCI_DEVICE_ID_INTEL_SBRIDGE_BR:
+                       pvt->pci_br0 = pdev;
                        break;
-               case 15:
-                       switch (func) {
-                       case 0:
-                               pvt->pci_ta = pdev;
-                               break;
-                       case 1:
-                               pvt->pci_ras = pdev;
-                               break;
-                       case 2:
-                       case 3:
-                       case 4:
-                       case 5:
-                               pvt->pci_tad[func - 2] = pdev;
-                               break;
-                       default:
-                               goto error;
-                       }
+               case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_HA0:
+                       pvt->pci_ha0 = pdev;
                        break;
-               case 17:
-                       switch (func) {
-                       case 0:
-                               pvt->pci_ddrio = pdev;
-                               break;
-                       default:
-                               goto error;
-                       }
+               case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA:
+                       pvt->pci_ta = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_RAS:
+                       pvt->pci_ras = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD0:
+               case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD1:
+               case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD2:
+               case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD3:
+               {
+                       int id = pdev->device - PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD0;
+                       pvt->pci_tad[id] = pdev;
+               }
+                       break;
+               case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_DDRIO:
+                       pvt->pci_ddrio = pdev;
                        break;
                default:
                        goto error;
                }
 
-               edac_dbg(0, "Associated PCI %02x.%02d.%d with dev = %p\n",
+               edac_dbg(0, "Associated PCI %02x:%02x, bus %d with dev = %p\n",
+                        pdev->vendor, pdev->device,
                         sbridge_dev->bus,
-                        PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
                         pdev);
        }
 
@@ -1488,9 +1646,8 @@ enodev:
        return -ENODEV;
 
 error:
-       sbridge_printk(KERN_ERR, "Device %d, function %d "
-                     "is out of the expected range\n",
-                     slot, func);
+       sbridge_printk(KERN_ERR, "Unexpected device %02x:%02x\n",
+                      PCI_VENDOR_ID_INTEL, pdev->device);
        return -EINVAL;
 }
 
@@ -1499,7 +1656,7 @@ static int ibridge_mci_bind_devs(struct mem_ctl_info *mci,
 {
        struct sbridge_pvt *pvt = mci->pvt_info;
        struct pci_dev *pdev, *tmp;
-       int i, func, slot;
+       int i;
        bool mode_2ha = false;
 
        tmp = pci_get_device(PCI_VENDOR_ID_INTEL,
@@ -1513,79 +1670,60 @@ static int ibridge_mci_bind_devs(struct mem_ctl_info *mci,
                pdev = sbridge_dev->pdev[i];
                if (!pdev)
                        continue;
-               slot = PCI_SLOT(pdev->devfn);
-               func = PCI_FUNC(pdev->devfn);
 
-               switch (slot) {
-               case 14:
-                       if (func == 0) {
-                               pvt->pci_ha0 = pdev;
-                               break;
-                       }
-                       goto error;
-               case 15:
-                       switch (func) {
-                       case 0:
-                               pvt->pci_ta = pdev;
-                               break;
-                       case 1:
-                               pvt->pci_ras = pdev;
-                               break;
-                       case 4:
-                       case 5:
-                               /* if we have 2 HAs active, channels 2 and 3
-                                * are in other device */
-                               if (mode_2ha)
-                                       break;
-                               /* fall through */
-                       case 2:
-                       case 3:
-                               pvt->pci_tad[func - 2] = pdev;
+               switch (pdev->device) {
+               case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0:
+                       pvt->pci_ha0 = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA:
+                       pvt->pci_ta = pdev;
+               case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_RAS:
+                       pvt->pci_ras = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD2:
+               case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD3:
+                       /* if we have 2 HAs active, channels 2 and 3
+                        * are in other device */
+                       if (mode_2ha)
                                break;
-                       default:
-                               goto error;
-                       }
+                       /* fall through */
+               case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD0:
+               case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD1:
+               {
+                       int id = pdev->device - PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD0;
+                       pvt->pci_tad[id] = pdev;
+               }
                        break;
-               case 17:
-                       if (func == 4) {
+               case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_2HA_DDRIO0:
+                       pvt->pci_ddrio = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_1HA_DDRIO0:
+                       if (!mode_2ha)
                                pvt->pci_ddrio = pdev;
-                               break;
-                       } else if (func == 0) {
-                               if (!mode_2ha)
-                                       pvt->pci_ddrio = pdev;
-                               break;
-                       }
-                       goto error;
-               case 22:
-                       switch (func) {
-                       case 0:
-                               pvt->pci_sad0 = pdev;
-                               break;
-                       case 1:
-                               pvt->pci_br0 = pdev;
-                               break;
-                       case 2:
-                               pvt->pci_br1 = pdev;
-                               break;
-                       default:
-                               goto error;
-                       }
                        break;
-               case 28:
-                       if (func == 0) {
-                               pvt->pci_ha1 = pdev;
-                               break;
-                       }
-                       goto error;
-               case 29:
+               case PCI_DEVICE_ID_INTEL_IBRIDGE_SAD:
+                       pvt->pci_sad0 = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_IBRIDGE_BR0:
+                       pvt->pci_br0 = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_IBRIDGE_BR1:
+                       pvt->pci_br1 = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1:
+                       pvt->pci_ha1 = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD0:
+               case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD1:
+               {
+                       int id = pdev->device - PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD0 + 2;
+
                        /* we shouldn't have this device if we have just one
                         * HA present */
                        WARN_ON(!mode_2ha);
-                       if (func == 2 || func == 3) {
-                               pvt->pci_tad[func] = pdev;
-                               break;
-                       }
-                       goto error;
+                       pvt->pci_tad[id] = pdev;
+               }
+                       break;
                default:
                        goto error;
                }
@@ -1614,11 +1752,111 @@ enodev:
 
 error:
        sbridge_printk(KERN_ERR,
-                      "Device %d, function %d is out of the expected range\n",
-                      slot, func);
+                      "Unexpected device %02x:%02x\n", PCI_VENDOR_ID_INTEL,
+                       pdev->device);
        return -EINVAL;
 }
 
+static int haswell_mci_bind_devs(struct mem_ctl_info *mci,
+                                struct sbridge_dev *sbridge_dev)
+{
+       struct sbridge_pvt *pvt = mci->pvt_info;
+       struct pci_dev *pdev, *tmp;
+       int i;
+       bool mode_2ha = false;
+
+       tmp = pci_get_device(PCI_VENDOR_ID_INTEL,
+                            PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1, NULL);
+       if (tmp) {
+               mode_2ha = true;
+               pci_dev_put(tmp);
+       }
+
+       /* there's only one device per system; not tied to any bus */
+       if (pvt->info.pci_vtd == NULL)
+               /* result will be checked later */
+               pvt->info.pci_vtd = pci_get_device(PCI_VENDOR_ID_INTEL,
+                                                  PCI_DEVICE_ID_INTEL_HASWELL_IMC_VTD_MISC,
+                                                  NULL);
+
+       for (i = 0; i < sbridge_dev->n_devs; i++) {
+               pdev = sbridge_dev->pdev[i];
+               if (!pdev)
+                       continue;
+
+               switch (pdev->device) {
+               case PCI_DEVICE_ID_INTEL_HASWELL_IMC_CBO_SAD0:
+                       pvt->pci_sad0 = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_HASWELL_IMC_CBO_SAD1:
+                       pvt->pci_sad1 = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0:
+                       pvt->pci_ha0 = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TA:
+                       pvt->pci_ta = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_THERMAL:
+                       pvt->pci_ras = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD0:
+                       pvt->pci_tad[0] = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD1:
+                       pvt->pci_tad[1] = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD2:
+                       if (!mode_2ha)
+                               pvt->pci_tad[2] = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD3:
+                       if (!mode_2ha)
+                               pvt->pci_tad[3] = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO0:
+                       pvt->pci_ddrio = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1:
+                       pvt->pci_ha1 = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TA:
+                       pvt->pci_ha1_ta = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD0:
+                       if (mode_2ha)
+                               pvt->pci_tad[2] = pdev;
+                       break;
+               case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD1:
+                       if (mode_2ha)
+                               pvt->pci_tad[3] = pdev;
+                       break;
+               default:
+                       break;
+               }
+
+               edac_dbg(0, "Associated PCI %02x.%02d.%d with dev = %p\n",
+                        sbridge_dev->bus,
+                        PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
+                        pdev);
+       }
+
+       /* Check if everything were registered */
+       if (!pvt->pci_sad0 || !pvt->pci_ha0 || !pvt->pci_sad1 ||
+           !pvt->pci_ras  || !pvt->pci_ta || !pvt->info.pci_vtd)
+               goto enodev;
+
+       for (i = 0; i < NUM_CHANNELS; i++) {
+               if (!pvt->pci_tad[i])
+                       goto enodev;
+       }
+       return 0;
+
+enodev:
+       sbridge_printk(KERN_ERR, "Some needed devices are missing\n");
+       return -ENODEV;
+}
+
 /****************************************************************************
                        Error check routines
  ****************************************************************************/
@@ -1736,6 +1974,9 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
         * EDAC core should be handling the channel mask, in order to point
         * to the group of dimm's where the error may be happening.
         */
+       if (!pvt->is_lockstep && !pvt->is_mirrored && !pvt->is_close_pg)
+               channel = first_channel;
+
        snprintf(msg, sizeof(msg),
                 "%s%s area:%s err_code:%04x:%04x socket:%d channel_mask:%ld rank:%d",
                 overflow ? " OVERFLOW" : "",
@@ -1865,10 +2106,6 @@ static int sbridge_mce_check_error(struct notifier_block *nb, unsigned long val,
                          "%u APIC %x\n", mce->cpuvendor, mce->cpuid,
                          mce->time, mce->socketid, mce->apicid);
 
-       /* Only handle if it is the right mc controller */
-       if (cpu_data(mce->cpu).phys_proc_id != pvt->sbridge_dev->mc)
-               return NOTIFY_DONE;
-
        smp_rmb();
        if ((pvt->mce_out + 1) % MCE_LOG_LEN == pvt->mce_in) {
                smp_wmb();
@@ -1932,7 +2169,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
        int rc;
 
        /* Check the number of active and not disabled channels */
-       rc = check_if_ecc_is_active(sbridge_dev->bus);
+       rc = check_if_ecc_is_active(sbridge_dev->bus, type);
        if (unlikely(rc < 0))
                return rc;
 
@@ -1971,11 +2208,15 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
        mci->edac_check = sbridge_check_error;
 
        pvt->info.type = type;
-       if (type == IVY_BRIDGE) {
+       switch (type) {
+       case IVY_BRIDGE:
                pvt->info.rankcfgr = IB_RANK_CFG_A;
                pvt->info.get_tolm = ibridge_get_tolm;
                pvt->info.get_tohm = ibridge_get_tohm;
                pvt->info.dram_rule = ibridge_dram_rule;
+               pvt->info.get_memory_type = get_memory_type;
+               pvt->info.get_node_id = get_node_id;
+               pvt->info.rir_limit = rir_limit;
                pvt->info.max_sad = ARRAY_SIZE(ibridge_dram_rule);
                pvt->info.interleave_list = ibridge_interleave_list;
                pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list);
@@ -1986,11 +2227,15 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
                rc = ibridge_mci_bind_devs(mci, sbridge_dev);
                if (unlikely(rc < 0))
                        goto fail0;
-       } else {
+               break;
+       case SANDY_BRIDGE:
                pvt->info.rankcfgr = SB_RANK_CFG_A;
                pvt->info.get_tolm = sbridge_get_tolm;
                pvt->info.get_tohm = sbridge_get_tohm;
                pvt->info.dram_rule = sbridge_dram_rule;
+               pvt->info.get_memory_type = get_memory_type;
+               pvt->info.get_node_id = get_node_id;
+               pvt->info.rir_limit = rir_limit;
                pvt->info.max_sad = ARRAY_SIZE(sbridge_dram_rule);
                pvt->info.interleave_list = sbridge_interleave_list;
                pvt->info.max_interleave = ARRAY_SIZE(sbridge_interleave_list);
@@ -2001,8 +2246,27 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
                rc = sbridge_mci_bind_devs(mci, sbridge_dev);
                if (unlikely(rc < 0))
                        goto fail0;
-       }
+               break;
+       case HASWELL:
+               /* rankcfgr isn't used */
+               pvt->info.get_tolm = haswell_get_tolm;
+               pvt->info.get_tohm = haswell_get_tohm;
+               pvt->info.dram_rule = ibridge_dram_rule;
+               pvt->info.get_memory_type = haswell_get_memory_type;
+               pvt->info.get_node_id = haswell_get_node_id;
+               pvt->info.rir_limit = haswell_rir_limit;
+               pvt->info.max_sad = ARRAY_SIZE(ibridge_dram_rule);
+               pvt->info.interleave_list = ibridge_interleave_list;
+               pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list);
+               pvt->info.interleave_pkg = ibridge_interleave_pkg;
+               mci->ctl_name = kasprintf(GFP_KERNEL, "Haswell Socket#%d", mci->mc_idx);
 
+               /* Store pci devices at mci for faster access */
+               rc = haswell_mci_bind_devs(mci, sbridge_dev);
+               if (unlikely(rc < 0))
+                       goto fail0;
+               break;
+       }
 
        /* Get dimm basic config and the memory layout */
        get_dimm_config(mci);
@@ -2037,10 +2301,10 @@ fail0:
 
 static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
-       int rc;
+       int rc = -ENODEV;
        u8 mc, num_mc = 0;
        struct sbridge_dev *sbridge_dev;
-       enum type type;
+       enum type type = SANDY_BRIDGE;
 
        /* get the pci devices we want to reserve for our use */
        mutex_lock(&sbridge_edac_lock);
@@ -2054,12 +2318,19 @@ static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        }
        probed++;
 
-       if (pdev->device == PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA) {
+       switch (pdev->device) {
+       case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA:
                rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_ibridge_table);
                type = IVY_BRIDGE;
-       } else {
+               break;
+       case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA:
                rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_sbridge_table);
                type = SANDY_BRIDGE;
+               break;
+       case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0:
+               rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_haswell_table);
+               type = HASWELL;
+               break;
        }
        if (unlikely(rc < 0))
                goto fail0;
@@ -2068,6 +2339,7 @@ static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        list_for_each_entry(sbridge_dev, &sbridge_edac_list, list) {
                edac_dbg(0, "Registering MC#%d (%d of %d)\n",
                         mc, mc + 1, num_mc);
+
                sbridge_dev->mc = mc++;
                rc = sbridge_register_mci(sbridge_dev, type);
                if (unlikely(rc < 0))
index f0a43646a2f3f4b36ddd64af33d39920c3cb006a..5abe943e34042df45d8d1f643b0334e6ceb19748 100644 (file)
@@ -481,7 +481,7 @@ EXPORT_SYMBOL_GPL(efivar_entry_remove);
  */
 static void efivar_entry_list_del_unlock(struct efivar_entry *entry)
 {
-       WARN_ON(!spin_is_locked(&__efivars->lock));
+       lockdep_assert_held(&__efivars->lock);
 
        list_del(&entry->list);
        spin_unlock_irq(&__efivars->lock);
@@ -507,7 +507,7 @@ int __efivar_entry_delete(struct efivar_entry *entry)
        const struct efivar_operations *ops = __efivars->ops;
        efi_status_t status;
 
-       WARN_ON(!spin_is_locked(&__efivars->lock));
+       lockdep_assert_held(&__efivars->lock);
 
        status = ops->set_variable(entry->var.VariableName,
                                   &entry->var.VendorGuid,
@@ -667,7 +667,7 @@ struct efivar_entry *efivar_entry_find(efi_char16_t *name, efi_guid_t guid,
        int strsize1, strsize2;
        bool found = false;
 
-       WARN_ON(!spin_is_locked(&__efivars->lock));
+       lockdep_assert_held(&__efivars->lock);
 
        list_for_each_entry_safe(entry, n, head, list) {
                strsize1 = ucs2_strsize(name, 1024);
@@ -739,7 +739,7 @@ int __efivar_entry_get(struct efivar_entry *entry, u32 *attributes,
        const struct efivar_operations *ops = __efivars->ops;
        efi_status_t status;
 
-       WARN_ON(!spin_is_locked(&__efivars->lock));
+       lockdep_assert_held(&__efivars->lock);
 
        status = ops->get_variable(entry->var.VariableName,
                                   &entry->var.VendorGuid,
index 41b2f40578d5e78e88ab1afdb1d5f066a3913658..954b9f6b0ef82eb74437e0efce4781b53ba58e0f 100644 (file)
@@ -90,7 +90,7 @@ struct gpio_desc *__must_check __devm_gpiod_get_index(struct device *dev,
        struct gpio_desc **dr;
        struct gpio_desc *desc;
 
-       dr = devres_alloc(devm_gpiod_release, sizeof(struct gpiod_desc *),
+       dr = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc *),
                          GFP_KERNEL);
        if (!dr)
                return ERR_PTR(-ENOMEM);
index 6557147d9331e252d38c566a07b61ada3b7a7f71..7e4c43c189600cc042248f21e8796c86acf79755 100644 (file)
@@ -241,9 +241,6 @@ static void bt8xxgpio_remove(struct pci_dev *pdev)
        bgwrite(~0x0, BT848_INT_STAT);
        bgwrite(0x0, BT848_GPIO_OUT_EN);
 
-       iounmap(bg->mmio);
-       release_mem_region(pci_resource_start(pdev, 0),
-                          pci_resource_len(pdev, 0));
        pci_disable_device(pdev);
 }
 
index ff9eb911b5e4267295404d6e6a5443571edeb166..fa945ec9ccff52ab54f34d6d535e8df4d4dc2fd1 100644 (file)
@@ -407,9 +407,27 @@ static int lp_gpio_runtime_resume(struct device *dev)
        return 0;
 }
 
+static int lp_gpio_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct lp_gpio *lg = platform_get_drvdata(pdev);
+       unsigned long reg;
+       int i;
+
+       /* on some hardware suspend clears input sensing, re-enable it here */
+       for (i = 0; i < lg->chip.ngpio; i++) {
+               if (gpiochip_is_requested(&lg->chip, i) != NULL) {
+                       reg = lp_gpio_reg(&lg->chip, i, LP_CONFIG2);
+                       outl(inl(reg) & ~GPINDIS_BIT, reg);
+               }
+       }
+       return 0;
+}
+
 static const struct dev_pm_ops lp_gpio_pm_ops = {
        .runtime_suspend = lp_gpio_runtime_suspend,
        .runtime_resume = lp_gpio_runtime_resume,
+       .resume = lp_gpio_resume,
 };
 
 static const struct acpi_device_id lynxpoint_gpio_acpi_match[] = {
index c3145f91fda32f62b60e3dde98c26b6830f5095e..31ad5df5dbc95d58c395dc27f865b0eb0ce036bc 100644 (file)
@@ -95,6 +95,9 @@ struct zynq_gpio {
        struct clk *clk;
 };
 
+static struct irq_chip zynq_gpio_level_irqchip;
+static struct irq_chip zynq_gpio_edge_irqchip;
+
 /**
  * zynq_gpio_get_bank_pin - Get the bank number and pin number within that bank
  * for a given pin in the GPIO device
@@ -410,6 +413,15 @@ static int zynq_gpio_set_irq_type(struct irq_data *irq_data, unsigned int type)
                       gpio->base_addr + ZYNQ_GPIO_INTPOL_OFFSET(bank_num));
        writel_relaxed(int_any,
                       gpio->base_addr + ZYNQ_GPIO_INTANY_OFFSET(bank_num));
+
+       if (type & IRQ_TYPE_LEVEL_MASK) {
+               __irq_set_chip_handler_name_locked(irq_data->irq,
+                       &zynq_gpio_level_irqchip, handle_fasteoi_irq, NULL);
+       } else {
+               __irq_set_chip_handler_name_locked(irq_data->irq,
+                       &zynq_gpio_edge_irqchip, handle_level_irq, NULL);
+       }
+
        return 0;
 }
 
@@ -424,9 +436,21 @@ static int zynq_gpio_set_wake(struct irq_data *data, unsigned int on)
 }
 
 /* irq chip descriptor */
-static struct irq_chip zynq_gpio_irqchip = {
+static struct irq_chip zynq_gpio_level_irqchip = {
        .name           = DRIVER_NAME,
        .irq_enable     = zynq_gpio_irq_enable,
+       .irq_eoi        = zynq_gpio_irq_ack,
+       .irq_mask       = zynq_gpio_irq_mask,
+       .irq_unmask     = zynq_gpio_irq_unmask,
+       .irq_set_type   = zynq_gpio_set_irq_type,
+       .irq_set_wake   = zynq_gpio_set_wake,
+       .flags          = IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED,
+};
+
+static struct irq_chip zynq_gpio_edge_irqchip = {
+       .name           = DRIVER_NAME,
+       .irq_enable     = zynq_gpio_irq_enable,
+       .irq_ack        = zynq_gpio_irq_ack,
        .irq_mask       = zynq_gpio_irq_mask,
        .irq_unmask     = zynq_gpio_irq_unmask,
        .irq_set_type   = zynq_gpio_set_irq_type,
@@ -469,10 +493,6 @@ static void zynq_gpio_irqhandler(unsigned int irq, struct irq_desc *desc)
                                                        offset);
                                generic_handle_irq(gpio_irq);
                        }
-
-                       /* clear IRQ in HW */
-                       writel_relaxed(int_sts, gpio->base_addr +
-                                       ZYNQ_GPIO_INTSTS_OFFSET(bank_num));
                }
        }
 
@@ -610,14 +630,14 @@ static int zynq_gpio_probe(struct platform_device *pdev)
                writel_relaxed(ZYNQ_GPIO_IXR_DISABLE_ALL, gpio->base_addr +
                               ZYNQ_GPIO_INTDIS_OFFSET(bank_num));
 
-       ret = gpiochip_irqchip_add(chip, &zynq_gpio_irqchip, 0,
-                                  handle_simple_irq, IRQ_TYPE_NONE);
+       ret = gpiochip_irqchip_add(chip, &zynq_gpio_edge_irqchip, 0,
+                                  handle_level_irq, IRQ_TYPE_NONE);
        if (ret) {
                dev_err(&pdev->dev, "Failed to add irq chip\n");
                goto err_rm_gpiochip;
        }
 
-       gpiochip_set_chained_irqchip(chip, &zynq_gpio_irqchip, irq,
+       gpiochip_set_chained_irqchip(chip, &zynq_gpio_edge_irqchip, irq,
                                     zynq_gpio_irqhandler);
 
        pm_runtime_set_active(&pdev->dev);
index 7cfdc22789053eacdb9b6dfc52f22d57ee00b41f..604dbe60bdee1abdddb8d706947391987628ab9e 100644 (file)
@@ -307,7 +307,5 @@ void of_gpiochip_add(struct gpio_chip *chip)
 void of_gpiochip_remove(struct gpio_chip *chip)
 {
        gpiochip_remove_pin_ranges(chip);
-
-       if (chip->of_node)
-               of_node_put(chip->of_node);
+       of_node_put(chip->of_node);
 }
index 4c761dcea97217e9495ed16a6403250ac04a7ff3..05c01ea8529487c9d37f32cd31237291728c82c9 100644 (file)
@@ -99,6 +99,7 @@ static struct ast_vbios_dclk_info dclk_table[] = {
        {0x25, 0x65, 0x80},                                     /* 16: VCLK88.75    */
        {0x77, 0x58, 0x80},                                     /* 17: VCLK119      */
        {0x32, 0x67, 0x80},                                 /* 18: VCLK85_5     */
+       {0x6a, 0x6d, 0x80},                                     /* 19: VCLK97_75        */
 };
 
 static struct ast_vbios_stdtable vbios_stdtable[] = {
index fa2be249999c70711e1b19cbe0df92fd5e081631..90e773019eac78f0a247f840eb5ada047a0b5573 100644 (file)
@@ -4696,8 +4696,9 @@ int drm_mode_create_dumb_ioctl(struct drm_device *dev,
                return -EINVAL;
 
        /* overflow checks for 32bit size calculations */
+       /* NOTE: DIV_ROUND_UP() can overflow */
        cpp = DIV_ROUND_UP(args->bpp, 8);
-       if (cpp > 0xffffffffU / args->width)
+       if (!cpp || cpp > 0xffffffffU / args->width)
                return -EINVAL;
        stride = cpp * args->width;
        if (args->height > 0xffffffffU / stride)
index ec96f9a9724c809363cd2cd88baf2cd7a31b9a3e..e27cdbe9d524a79dbd4168febc15de0660e82d9f 100644 (file)
@@ -494,6 +494,36 @@ bool i915_semaphore_is_enabled(struct drm_device *dev)
        return true;
 }
 
+void intel_hpd_cancel_work(struct drm_i915_private *dev_priv)
+{
+       spin_lock_irq(&dev_priv->irq_lock);
+
+       dev_priv->long_hpd_port_mask = 0;
+       dev_priv->short_hpd_port_mask = 0;
+       dev_priv->hpd_event_bits = 0;
+
+       spin_unlock_irq(&dev_priv->irq_lock);
+
+       cancel_work_sync(&dev_priv->dig_port_work);
+       cancel_work_sync(&dev_priv->hotplug_work);
+       cancel_delayed_work_sync(&dev_priv->hotplug_reenable_work);
+}
+
+static void intel_suspend_encoders(struct drm_i915_private *dev_priv)
+{
+       struct drm_device *dev = dev_priv->dev;
+       struct drm_encoder *encoder;
+
+       drm_modeset_lock_all(dev);
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+               struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
+
+               if (intel_encoder->suspend)
+                       intel_encoder->suspend(intel_encoder);
+       }
+       drm_modeset_unlock_all(dev);
+}
+
 static int i915_drm_freeze(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -538,6 +568,9 @@ static int i915_drm_freeze(struct drm_device *dev)
                flush_delayed_work(&dev_priv->rps.delayed_resume_work);
 
                intel_runtime_pm_disable_interrupts(dev);
+               intel_hpd_cancel_work(dev_priv);
+
+               intel_suspend_encoders(dev_priv);
 
                intel_suspend_gt_powersave(dev);
 
index 4412f6a4383bd2af5df6d5119e3f0f044bed59e5..7a830eac5ba30a7859eb65313d9ee567c5d324eb 100644 (file)
@@ -1458,7 +1458,7 @@ struct drm_i915_private {
                } hpd_mark;
        } hpd_stats[HPD_NUM_PINS];
        u32 hpd_event_bits;
-       struct timer_list hotplug_reenable_timer;
+       struct delayed_work hotplug_reenable_work;
 
        struct i915_fbc fbc;
        struct i915_drrs drrs;
@@ -2178,6 +2178,7 @@ extern unsigned long i915_mch_val(struct drm_i915_private *dev_priv);
 extern unsigned long i915_gfx_val(struct drm_i915_private *dev_priv);
 extern void i915_update_gfx_val(struct drm_i915_private *dev_priv);
 int vlv_force_gfx_clock(struct drm_i915_private *dev_priv, bool on);
+void intel_hpd_cancel_work(struct drm_i915_private *dev_priv);
 
 extern void intel_console_resume(struct work_struct *work);
 
index 390ccc2a3096670d636af14a0164dd237a43d66c..0050ee9470f196748621b96ffd001cd3e4cd85d8 100644 (file)
@@ -1189,8 +1189,8 @@ static void i915_hotplug_work_func(struct work_struct *work)
          * some connectors */
        if (hpd_disabled) {
                drm_kms_helper_poll_enable(dev);
-               mod_timer(&dev_priv->hotplug_reenable_timer,
-                         jiffies + msecs_to_jiffies(I915_REENABLE_HOTPLUG_DELAY));
+               mod_delayed_work(system_wq, &dev_priv->hotplug_reenable_work,
+                                msecs_to_jiffies(I915_REENABLE_HOTPLUG_DELAY));
        }
 
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
@@ -1213,11 +1213,6 @@ static void i915_hotplug_work_func(struct work_struct *work)
                drm_kms_helper_hotplug_event(dev);
 }
 
-static void intel_hpd_irq_uninstall(struct drm_i915_private *dev_priv)
-{
-       del_timer_sync(&dev_priv->hotplug_reenable_timer);
-}
-
 static void ironlake_rps_change_irq_handler(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -3892,8 +3887,6 @@ static void gen8_irq_uninstall(struct drm_device *dev)
        if (!dev_priv)
                return;
 
-       intel_hpd_irq_uninstall(dev_priv);
-
        gen8_irq_reset(dev);
 }
 
@@ -3908,8 +3901,6 @@ static void valleyview_irq_uninstall(struct drm_device *dev)
 
        I915_WRITE(VLV_MASTER_IER, 0);
 
-       intel_hpd_irq_uninstall(dev_priv);
-
        for_each_pipe(pipe)
                I915_WRITE(PIPESTAT(pipe), 0xffff);
 
@@ -3988,8 +3979,6 @@ static void ironlake_irq_uninstall(struct drm_device *dev)
        if (!dev_priv)
                return;
 
-       intel_hpd_irq_uninstall(dev_priv);
-
        ironlake_irq_reset(dev);
 }
 
@@ -4360,8 +4349,6 @@ static void i915_irq_uninstall(struct drm_device * dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int pipe;
 
-       intel_hpd_irq_uninstall(dev_priv);
-
        if (I915_HAS_HOTPLUG(dev)) {
                I915_WRITE(PORT_HOTPLUG_EN, 0);
                I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
@@ -4598,8 +4585,6 @@ static void i965_irq_uninstall(struct drm_device * dev)
        if (!dev_priv)
                return;
 
-       intel_hpd_irq_uninstall(dev_priv);
-
        I915_WRITE(PORT_HOTPLUG_EN, 0);
        I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
 
@@ -4615,14 +4600,18 @@ static void i965_irq_uninstall(struct drm_device * dev)
        I915_WRITE(IIR, I915_READ(IIR));
 }
 
-static void intel_hpd_irq_reenable(unsigned long data)
+static void intel_hpd_irq_reenable(struct work_struct *work)
 {
-       struct drm_i915_private *dev_priv = (struct drm_i915_private *)data;
+       struct drm_i915_private *dev_priv =
+               container_of(work, typeof(*dev_priv),
+                            hotplug_reenable_work.work);
        struct drm_device *dev = dev_priv->dev;
        struct drm_mode_config *mode_config = &dev->mode_config;
        unsigned long irqflags;
        int i;
 
+       intel_runtime_pm_get(dev_priv);
+
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
        for (i = (HPD_NONE + 1); i < HPD_NUM_PINS; i++) {
                struct drm_connector *connector;
@@ -4648,6 +4637,8 @@ static void intel_hpd_irq_reenable(unsigned long data)
        if (dev_priv->display.hpd_irq_setup)
                dev_priv->display.hpd_irq_setup(dev);
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+
+       intel_runtime_pm_put(dev_priv);
 }
 
 void intel_irq_init(struct drm_device *dev)
@@ -4670,8 +4661,8 @@ void intel_irq_init(struct drm_device *dev)
        setup_timer(&dev_priv->gpu_error.hangcheck_timer,
                    i915_hangcheck_elapsed,
                    (unsigned long) dev);
-       setup_timer(&dev_priv->hotplug_reenable_timer, intel_hpd_irq_reenable,
-                   (unsigned long) dev_priv);
+       INIT_DELAYED_WORK(&dev_priv->hotplug_reenable_work,
+                         intel_hpd_irq_reenable);
 
        pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
 
index a66955037e4e2f30bb9662fed0be12a02d5deaf2..eee79e1c322253165a4c58cff448fa401119abcd 100644 (file)
@@ -1123,7 +1123,7 @@ init_vbt_defaults(struct drm_i915_private *dev_priv)
        }
 }
 
-static int __init intel_no_opregion_vbt_callback(const struct dmi_system_id *id)
+static int intel_no_opregion_vbt_callback(const struct dmi_system_id *id)
 {
        DRM_DEBUG_KMS("Falling back to manually reading VBT from "
                      "VBIOS ROM for %s\n",
index 2efaf8e8d9c49b6ca47491e8d5693f2072c8a333..9212e6504e0f1a2867ae7913d01cf019107d77b0 100644 (file)
@@ -699,16 +699,21 @@ intel_crt_detect(struct drm_connector *connector, bool force)
                goto out;
        }
 
+       drm_modeset_acquire_init(&ctx, 0);
+
        /* for pre-945g platforms use load detect */
        if (intel_get_load_detect_pipe(connector, NULL, &tmp, &ctx)) {
                if (intel_crt_detect_ddc(connector))
                        status = connector_status_connected;
                else
                        status = intel_crt_load_detect(crt);
-               intel_release_load_detect_pipe(connector, &tmp, &ctx);
+               intel_release_load_detect_pipe(connector, &tmp);
        } else
                status = connector_status_unknown;
 
+       drm_modeset_drop_locks(&ctx);
+       drm_modeset_acquire_fini(&ctx);
+
 out:
        intel_display_power_put(dev_priv, power_domain);
        return status;
@@ -799,7 +804,7 @@ static const struct drm_encoder_funcs intel_crt_enc_funcs = {
        .destroy = intel_encoder_destroy,
 };
 
-static int __init intel_no_crt_dmi_callback(const struct dmi_system_id *id)
+static int intel_no_crt_dmi_callback(const struct dmi_system_id *id)
 {
        DRM_INFO("Skipping CRT initialization for %s\n", id->ident);
        return 1;
index 018fb7222f60ecee10fcb0f2db65e89d29c42e0f..d8324c69fa868de2364cf1b272426f5a634c5c31 100644 (file)
@@ -2233,6 +2233,15 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev,
        if (need_vtd_wa(dev) && alignment < 256 * 1024)
                alignment = 256 * 1024;
 
+       /*
+        * Global gtt pte registers are special registers which actually forward
+        * writes to a chunk of system memory. Which means that there is no risk
+        * that the register values disappear as soon as we call
+        * intel_runtime_pm_put(), so it is correct to wrap only the
+        * pin/unpin/fence and not more.
+        */
+       intel_runtime_pm_get(dev_priv);
+
        dev_priv->mm.interruptible = false;
        ret = i915_gem_object_pin_to_display_plane(obj, alignment, pipelined);
        if (ret)
@@ -2250,12 +2259,14 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev,
        i915_gem_object_pin_fence(obj);
 
        dev_priv->mm.interruptible = true;
+       intel_runtime_pm_put(dev_priv);
        return 0;
 
 err_unpin:
        i915_gem_object_unpin_from_display_plane(obj);
 err_interruptible:
        dev_priv->mm.interruptible = true;
+       intel_runtime_pm_put(dev_priv);
        return ret;
 }
 
@@ -4188,10 +4199,6 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
                intel_set_pch_fifo_underrun_reporting(dev, pipe, false);
 
        intel_disable_pipe(dev_priv, pipe);
-
-       if (intel_crtc->config.dp_encoder_is_mst)
-               intel_ddi_set_vc_payload_alloc(crtc, false);
-
        ironlake_pfit_disable(intel_crtc);
 
        for_each_encoder_on_crtc(dev, crtc, encoder)
@@ -4256,6 +4263,9 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
                intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A, false);
        intel_disable_pipe(dev_priv, pipe);
 
+       if (intel_crtc->config.dp_encoder_is_mst)
+               intel_ddi_set_vc_payload_alloc(crtc, false);
+
        intel_ddi_disable_transcoder_func(dev_priv, cpu_transcoder);
 
        ironlake_pfit_disable(intel_crtc);
@@ -8240,6 +8250,15 @@ static int intel_crtc_cursor_set_obj(struct drm_crtc *crtc,
                        goto fail_locked;
                }
 
+               /*
+                * Global gtt pte registers are special registers which actually
+                * forward writes to a chunk of system memory. Which means that
+                * there is no risk that the register values disappear as soon
+                * as we call intel_runtime_pm_put(), so it is correct to wrap
+                * only the pin/unpin/fence and not more.
+                */
+               intel_runtime_pm_get(dev_priv);
+
                /* Note that the w/a also requires 2 PTE of padding following
                 * the bo. We currently fill all unused PTE with the shadow
                 * page and so we should always have valid PTE following the
@@ -8252,16 +8271,20 @@ static int intel_crtc_cursor_set_obj(struct drm_crtc *crtc,
                ret = i915_gem_object_pin_to_display_plane(obj, alignment, NULL);
                if (ret) {
                        DRM_DEBUG_KMS("failed to move cursor bo into the GTT\n");
+                       intel_runtime_pm_put(dev_priv);
                        goto fail_locked;
                }
 
                ret = i915_gem_object_put_fence(obj);
                if (ret) {
                        DRM_DEBUG_KMS("failed to release fence for cursor");
+                       intel_runtime_pm_put(dev_priv);
                        goto fail_unpin;
                }
 
                addr = i915_gem_obj_ggtt_offset(obj);
+
+               intel_runtime_pm_put(dev_priv);
        } else {
                int align = IS_I830(dev) ? 16 * 1024 : 256;
                ret = i915_gem_object_attach_phys(obj, align);
@@ -8462,8 +8485,6 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
                      connector->base.id, connector->name,
                      encoder->base.id, encoder->name);
 
-       drm_modeset_acquire_init(ctx, 0);
-
 retry:
        ret = drm_modeset_lock(&config->connection_mutex, ctx);
        if (ret)
@@ -8502,10 +8523,14 @@ retry:
                i++;
                if (!(encoder->possible_crtcs & (1 << i)))
                        continue;
-               if (!possible_crtc->enabled) {
-                       crtc = possible_crtc;
-                       break;
-               }
+               if (possible_crtc->enabled)
+                       continue;
+               /* This can occur when applying the pipe A quirk on resume. */
+               if (to_intel_crtc(possible_crtc)->new_enabled)
+                       continue;
+
+               crtc = possible_crtc;
+               break;
        }
 
        /*
@@ -8574,15 +8599,11 @@ fail_unlock:
                goto retry;
        }
 
-       drm_modeset_drop_locks(ctx);
-       drm_modeset_acquire_fini(ctx);
-
        return false;
 }
 
 void intel_release_load_detect_pipe(struct drm_connector *connector,
-                                   struct intel_load_detect_pipe *old,
-                                   struct drm_modeset_acquire_ctx *ctx)
+                                   struct intel_load_detect_pipe *old)
 {
        struct intel_encoder *intel_encoder =
                intel_attached_encoder(connector);
@@ -8606,17 +8627,12 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
                        drm_framebuffer_unreference(old->release_fb);
                }
 
-               goto unlock;
                return;
        }
 
        /* Switch crtc and encoder back off if necessary */
        if (old->dpms_mode != DRM_MODE_DPMS_ON)
                connector->funcs->dpms(connector, old->dpms_mode);
-
-unlock:
-       drm_modeset_drop_locks(ctx);
-       drm_modeset_acquire_fini(ctx);
 }
 
 static int i9xx_pll_refclk(struct drm_device *dev,
@@ -11700,8 +11716,8 @@ intel_cursor_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
        };
        const struct drm_rect clip = {
                /* integer pixels */
-               .x2 = intel_crtc->config.pipe_src_w,
-               .y2 = intel_crtc->config.pipe_src_h,
+               .x2 = intel_crtc->active ? intel_crtc->config.pipe_src_w : 0,
+               .y2 = intel_crtc->active ? intel_crtc->config.pipe_src_h : 0,
        };
        bool visible;
        int ret;
@@ -12488,6 +12504,9 @@ static struct intel_quirk intel_quirks[] = {
        /* Acer C720 and C720P Chromebooks (Celeron 2955U) have backlights */
        { 0x0a06, 0x1025, 0x0a11, quirk_backlight_present },
 
+       /* Acer C720 Chromebook (Core i3 4005U) */
+       { 0x0a16, 0x1025, 0x0a11, quirk_backlight_present },
+
        /* Toshiba CB35 Chromebook (Celeron 2955U) */
        { 0x0a06, 0x1179, 0x0a88, quirk_backlight_present },
 
@@ -12659,7 +12678,7 @@ static void intel_enable_pipe_a(struct drm_device *dev)
        struct intel_connector *connector;
        struct drm_connector *crt = NULL;
        struct intel_load_detect_pipe load_detect_temp;
-       struct drm_modeset_acquire_ctx ctx;
+       struct drm_modeset_acquire_ctx *ctx = dev->mode_config.acquire_ctx;
 
        /* We can't just switch on the pipe A, we need to set things up with a
         * proper mode and output configuration. As a gross hack, enable pipe A
@@ -12676,10 +12695,8 @@ static void intel_enable_pipe_a(struct drm_device *dev)
        if (!crt)
                return;
 
-       if (intel_get_load_detect_pipe(crt, NULL, &load_detect_temp, &ctx))
-               intel_release_load_detect_pipe(crt, &load_detect_temp, &ctx);
-
-
+       if (intel_get_load_detect_pipe(crt, NULL, &load_detect_temp, ctx))
+               intel_release_load_detect_pipe(crt, &load_detect_temp);
 }
 
 static bool
@@ -13112,7 +13129,7 @@ void intel_modeset_cleanup(struct drm_device *dev)
         * experience fancy races otherwise.
         */
        drm_irq_uninstall(dev);
-       cancel_work_sync(&dev_priv->hotplug_work);
+       intel_hpd_cancel_work(dev_priv);
        dev_priv->pm._irqs_disabled = true;
 
        /*
index ee3942f0b0683f5747c53842cb7f9ae0dc6745fa..81d7681faa638f1c7879b5cd0aafb3f56a948adf 100644 (file)
@@ -3553,6 +3553,9 @@ intel_dp_check_link_status(struct intel_dp *intel_dp)
        if (WARN_ON(!intel_encoder->base.crtc))
                return;
 
+       if (!to_intel_crtc(intel_encoder->base.crtc)->active)
+               return;
+
        /* Try to read receiver status if the link appears to be up */
        if (!intel_dp_get_link_status(intel_dp, link_status)) {
                return;
@@ -3658,24 +3661,12 @@ ironlake_dp_detect(struct intel_dp *intel_dp)
        return intel_dp_detect_dpcd(intel_dp);
 }
 
-static enum drm_connector_status
-g4x_dp_detect(struct intel_dp *intel_dp)
+static int g4x_digital_port_connected(struct drm_device *dev,
+                                      struct intel_digital_port *intel_dig_port)
 {
-       struct drm_device *dev = intel_dp_to_dev(intel_dp);
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
        uint32_t bit;
 
-       /* Can't disconnect eDP, but you can close the lid... */
-       if (is_edp(intel_dp)) {
-               enum drm_connector_status status;
-
-               status = intel_panel_detect(dev);
-               if (status == connector_status_unknown)
-                       status = connector_status_connected;
-               return status;
-       }
-
        if (IS_VALLEYVIEW(dev)) {
                switch (intel_dig_port->port) {
                case PORT_B:
@@ -3688,7 +3679,7 @@ g4x_dp_detect(struct intel_dp *intel_dp)
                        bit = PORTD_HOTPLUG_LIVE_STATUS_VLV;
                        break;
                default:
-                       return connector_status_unknown;
+                       return -EINVAL;
                }
        } else {
                switch (intel_dig_port->port) {
@@ -3702,11 +3693,36 @@ g4x_dp_detect(struct intel_dp *intel_dp)
                        bit = PORTD_HOTPLUG_LIVE_STATUS_G4X;
                        break;
                default:
-                       return connector_status_unknown;
+                       return -EINVAL;
                }
        }
 
        if ((I915_READ(PORT_HOTPLUG_STAT) & bit) == 0)
+               return 0;
+       return 1;
+}
+
+static enum drm_connector_status
+g4x_dp_detect(struct intel_dp *intel_dp)
+{
+       struct drm_device *dev = intel_dp_to_dev(intel_dp);
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       int ret;
+
+       /* Can't disconnect eDP, but you can close the lid... */
+       if (is_edp(intel_dp)) {
+               enum drm_connector_status status;
+
+               status = intel_panel_detect(dev);
+               if (status == connector_status_unknown)
+                       status = connector_status_connected;
+               return status;
+       }
+
+       ret = g4x_digital_port_connected(dev, intel_dig_port);
+       if (ret == -EINVAL)
+               return connector_status_unknown;
+       else if (ret == 0)
                return connector_status_disconnected;
 
        return intel_dp_detect_dpcd(intel_dp);
@@ -4003,6 +4019,16 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder)
        kfree(intel_dig_port);
 }
 
+static void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder)
+{
+       struct intel_dp *intel_dp = enc_to_intel_dp(&intel_encoder->base);
+
+       if (!is_edp(intel_dp))
+               return;
+
+       edp_panel_vdd_off_sync(intel_dp);
+}
+
 static void intel_dp_encoder_reset(struct drm_encoder *encoder)
 {
        intel_edp_panel_vdd_sanitize(to_intel_encoder(encoder));
@@ -4037,18 +4063,30 @@ bool
 intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
 {
        struct intel_dp *intel_dp = &intel_dig_port->dp;
+       struct intel_encoder *intel_encoder = &intel_dig_port->base;
        struct drm_device *dev = intel_dig_port->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       int ret;
+       enum intel_display_power_domain power_domain;
+       bool ret = true;
+
        if (intel_dig_port->base.type != INTEL_OUTPUT_EDP)
                intel_dig_port->base.type = INTEL_OUTPUT_DISPLAYPORT;
 
        DRM_DEBUG_KMS("got hpd irq on port %d - %s\n", intel_dig_port->port,
                      long_hpd ? "long" : "short");
 
+       power_domain = intel_display_port_power_domain(intel_encoder);
+       intel_display_power_get(dev_priv, power_domain);
+
        if (long_hpd) {
-               if (!ibx_digital_port_connected(dev_priv, intel_dig_port))
-                       goto mst_fail;
+
+               if (HAS_PCH_SPLIT(dev)) {
+                       if (!ibx_digital_port_connected(dev_priv, intel_dig_port))
+                               goto mst_fail;
+               } else {
+                       if (g4x_digital_port_connected(dev, intel_dig_port) != 1)
+                               goto mst_fail;
+               }
 
                if (!intel_dp_get_dpcd(intel_dp)) {
                        goto mst_fail;
@@ -4061,8 +4099,7 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
 
        } else {
                if (intel_dp->is_mst) {
-                       ret = intel_dp_check_mst_status(intel_dp);
-                       if (ret == -EINVAL)
+                       if (intel_dp_check_mst_status(intel_dp) == -EINVAL)
                                goto mst_fail;
                }
 
@@ -4076,7 +4113,8 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
                        drm_modeset_unlock(&dev->mode_config.connection_mutex);
                }
        }
-       return false;
+       ret = false;
+       goto put_power;
 mst_fail:
        /* if we were in MST mode, and device is not there get out of MST mode */
        if (intel_dp->is_mst) {
@@ -4084,7 +4122,10 @@ mst_fail:
                intel_dp->is_mst = false;
                drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr, intel_dp->is_mst);
        }
-       return true;
+put_power:
+       intel_display_power_put(dev_priv, power_domain);
+
+       return ret;
 }
 
 /* Return which DP Port should be selected for Transcoder DP control */
@@ -4722,6 +4763,7 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
        intel_encoder->disable = intel_disable_dp;
        intel_encoder->get_hw_state = intel_dp_get_hw_state;
        intel_encoder->get_config = intel_dp_get_config;
+       intel_encoder->suspend = intel_dp_encoder_suspend;
        if (IS_CHERRYVIEW(dev)) {
                intel_encoder->pre_pll_enable = chv_dp_pre_pll_enable;
                intel_encoder->pre_enable = chv_pre_enable_dp;
index 4b2664bd5b81d0afa2b59ae403c850549e2e5b10..b8c8bbd8e5f990b256ffe20f853395dbe6e784a2 100644 (file)
@@ -153,6 +153,12 @@ struct intel_encoder {
         * be set correctly before calling this function. */
        void (*get_config)(struct intel_encoder *,
                           struct intel_crtc_config *pipe_config);
+       /*
+        * Called during system suspend after all pending requests for the
+        * encoder are flushed (for example for DP AUX transactions) and
+        * device interrupts are disabled.
+        */
+       void (*suspend)(struct intel_encoder *);
        int crtc_mask;
        enum hpd_pin hpd_pin;
 };
@@ -830,8 +836,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
                                struct intel_load_detect_pipe *old,
                                struct drm_modeset_acquire_ctx *ctx);
 void intel_release_load_detect_pipe(struct drm_connector *connector,
-                                   struct intel_load_detect_pipe *old,
-                                   struct drm_modeset_acquire_ctx *ctx);
+                                   struct intel_load_detect_pipe *old);
 int intel_pin_and_fence_fb_obj(struct drm_device *dev,
                               struct drm_i915_gem_object *obj,
                               struct intel_engine_cs *pipelined);
index 881361c0f27e746097414a5ddc30448227175602..fdf40267249c1031a4a52a8f110b41fbf93ff61f 100644 (file)
@@ -538,7 +538,7 @@ static const struct drm_encoder_funcs intel_lvds_enc_funcs = {
        .destroy = intel_encoder_destroy,
 };
 
-static int __init intel_no_lvds_dmi_callback(const struct dmi_system_id *id)
+static int intel_no_lvds_dmi_callback(const struct dmi_system_id *id)
 {
        DRM_INFO("Skipping LVDS initialization for %s\n", id->ident);
        return 1;
index 59b028f0b1e8c7a652cc174c17373b90a4782077..8e374449c6b562356f47ac2ba169f974f8e7226f 100644 (file)
@@ -801,7 +801,7 @@ static void pch_enable_backlight(struct intel_connector *connector)
 
        cpu_ctl2 = I915_READ(BLC_PWM_CPU_CTL2);
        if (cpu_ctl2 & BLM_PWM_ENABLE) {
-               WARN(1, "cpu backlight already enabled\n");
+               DRM_DEBUG_KMS("cpu backlight already enabled\n");
                cpu_ctl2 &= ~BLM_PWM_ENABLE;
                I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2);
        }
@@ -845,7 +845,7 @@ static void i9xx_enable_backlight(struct intel_connector *connector)
 
        ctl = I915_READ(BLC_PWM_CTL);
        if (ctl & BACKLIGHT_DUTY_CYCLE_MASK_PNV) {
-               WARN(1, "backlight already enabled\n");
+               DRM_DEBUG_KMS("backlight already enabled\n");
                I915_WRITE(BLC_PWM_CTL, 0);
        }
 
@@ -876,7 +876,7 @@ static void i965_enable_backlight(struct intel_connector *connector)
 
        ctl2 = I915_READ(BLC_PWM_CTL2);
        if (ctl2 & BLM_PWM_ENABLE) {
-               WARN(1, "backlight already enabled\n");
+               DRM_DEBUG_KMS("backlight already enabled\n");
                ctl2 &= ~BLM_PWM_ENABLE;
                I915_WRITE(BLC_PWM_CTL2, ctl2);
        }
@@ -910,7 +910,7 @@ static void vlv_enable_backlight(struct intel_connector *connector)
 
        ctl2 = I915_READ(VLV_BLC_PWM_CTL2(pipe));
        if (ctl2 & BLM_PWM_ENABLE) {
-               WARN(1, "backlight already enabled\n");
+               DRM_DEBUG_KMS("backlight already enabled\n");
                ctl2 &= ~BLM_PWM_ENABLE;
                I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2);
        }
index e211eef4b7e4cac5a1eae5c88119537621f788a8..c69d3ce1b3d69a6f7e9c943ed5be3dc68decdde7 100644 (file)
@@ -1311,6 +1311,7 @@ intel_tv_detect(struct drm_connector *connector, bool force)
 {
        struct drm_display_mode mode;
        struct intel_tv *intel_tv = intel_attached_tv(connector);
+       enum drm_connector_status status;
        int type;
 
        DRM_DEBUG_KMS("[CONNECTOR:%d:%s] force=%d\n",
@@ -1323,16 +1324,24 @@ intel_tv_detect(struct drm_connector *connector, bool force)
                struct intel_load_detect_pipe tmp;
                struct drm_modeset_acquire_ctx ctx;
 
+               drm_modeset_acquire_init(&ctx, 0);
+
                if (intel_get_load_detect_pipe(connector, &mode, &tmp, &ctx)) {
                        type = intel_tv_detect_type(intel_tv, connector);
-                       intel_release_load_detect_pipe(connector, &tmp, &ctx);
+                       intel_release_load_detect_pipe(connector, &tmp);
+                       status = type < 0 ?
+                               connector_status_disconnected :
+                               connector_status_connected;
                } else
-                       return connector_status_unknown;
+                       status = connector_status_unknown;
+
+               drm_modeset_drop_locks(&ctx);
+               drm_modeset_acquire_fini(&ctx);
        } else
                return connector->status;
 
-       if (type < 0)
-               return connector_status_disconnected;
+       if (status != connector_status_connected)
+               return status;
 
        intel_tv->type = type;
        intel_tv_find_better_format(connector);
index 74cebb51e8c285e23475c6df40ae64a271857b9f..c6c80ea28c35809dbe63bb22aec0a50da9f4d0c6 100644 (file)
@@ -397,6 +397,7 @@ static void mdp4_crtc_prepare(struct drm_crtc *crtc)
        struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
        DBG("%s", mdp4_crtc->name);
        /* make sure we hold a ref to mdp clks while setting up mode: */
+       drm_crtc_vblank_get(crtc);
        mdp4_enable(get_kms(crtc));
        mdp4_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
 }
@@ -407,6 +408,7 @@ static void mdp4_crtc_commit(struct drm_crtc *crtc)
        crtc_flush(crtc);
        /* drop the ref to mdp clk's that we got in prepare: */
        mdp4_disable(get_kms(crtc));
+       drm_crtc_vblank_put(crtc);
 }
 
 static int mdp4_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
index b447c01ad89c86c909b92679444843989df22c9e..26ee80db17af9fec7308f2e4defbac06f6dd6d3d 100644 (file)
@@ -974,12 +974,11 @@ static int msm_pdev_probe(struct platform_device *pdev)
 
        for (i = 0; i < ARRAY_SIZE(devnames); i++) {
                struct device *dev;
-               int ret;
 
                dev = bus_find_device_by_name(&platform_bus_type,
                                NULL, devnames[i]);
                if (!dev) {
-                       dev_info(master, "still waiting for %s\n", devnames[i]);
+                       dev_info(&pdev->dev, "still waiting for %s\n", devnames[i]);
                        return -EPROBE_DEFER;
                }
 
index 9c5221ce391ab063cac34ebce428e46939828649..ab5bfd2d0ebf2e29897fa56e1df2c77c0f47aeb8 100644 (file)
@@ -143,7 +143,7 @@ static int msm_fbdev_create(struct drm_fb_helper *helper,
        ret = msm_gem_get_iova_locked(fbdev->bo, 0, &paddr);
        if (ret) {
                dev_err(dev->dev, "failed to get buffer obj iova: %d\n", ret);
-               goto fail;
+               goto fail_unlock;
        }
 
        fbi = framebuffer_alloc(0, dev->dev);
index 099af483fdf0328925b23be1fc9c635a5c4c63ba..7acdaa5688b77e89f3afa786da19903d0d0c7b6d 100644 (file)
@@ -27,8 +27,8 @@ struct msm_iommu {
 static int msm_fault_handler(struct iommu_domain *iommu, struct device *dev,
                unsigned long iova, int flags, void *arg)
 {
-       DBG("*** fault: iova=%08lx, flags=%d", iova, flags);
-       return -ENOSYS;
+       pr_warn_ratelimited("*** fault: iova=%08lx, flags=%d\n", iova, flags);
+       return 0;
 }
 
 static int msm_iommu_attach(struct msm_mmu *mmu, const char **names, int cnt)
index 10598dede9e97fdaa108f2e37c2332fb04d9ed4f..68bf06768123bb2d2fa92b0bf7777a28ad08f9c8 100644 (file)
@@ -132,12 +132,12 @@ nvkm_client_notify_new(struct nouveau_client *client,
                if (ret == 0) {
                        client->notify[index] = notify;
                        notify->client = client;
-                       return 0;
+                       return index;
                }
        }
 
        kfree(notify);
-       return 0;
+       return ret;
 }
 
 static int
index 8701968a9743aa7540cdfc0759919c058a45a3fa..30a2911878f893fce40885f2aeb6d8b6bf4d60a3 100644 (file)
@@ -86,7 +86,7 @@ nouveau_parent_lclass(struct nouveau_object *parent, u32 *lclass, int size)
        sclass = nv_parent(parent)->sclass;
        while (sclass) {
                if (++nr < size)
-                       lclass[nr] = sclass->oclass->handle;
+                       lclass[nr] = sclass->oclass->handle & 0xffff;
                sclass = sclass->sclass;
        }
 
@@ -96,7 +96,7 @@ nouveau_parent_lclass(struct nouveau_object *parent, u32 *lclass, int size)
                if (engine && (oclass = engine->sclass)) {
                        while (oclass->ofuncs) {
                                if (++nr < size)
-                                       lclass[nr] = oclass->handle;
+                                       lclass[nr] = oclass->handle & 0xffff;
                                oclass++;
                        }
                }
index 54ec53bc6252495b973499a1f089847674b1847b..cdf9147f32a1e80df5c5e58fa840ce311fa54819 100644 (file)
@@ -163,6 +163,7 @@ nve0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &gk20a_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  gk20a_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_LTC    ] =  gk104_ltc_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &gk20a_ibus_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
index db19191176fa513ed958377fdceb1a4e6a735afd..30fd1dc64f9307603e137c43d5f6bf0e76e05d4f 100644 (file)
@@ -68,6 +68,9 @@ nvc0_graph_zbc_color_get(struct nvc0_graph_priv *priv, int format,
                }
        }
 
+       if (zbc < 0)
+               return zbc;
+
        memcpy(priv->zbc_color[zbc].ds, ds, sizeof(priv->zbc_color[zbc].ds));
        memcpy(priv->zbc_color[zbc].l2, l2, sizeof(priv->zbc_color[zbc].l2));
        priv->zbc_color[zbc].format = format;
@@ -109,6 +112,9 @@ nvc0_graph_zbc_depth_get(struct nvc0_graph_priv *priv, int format,
                }
        }
 
+       if (zbc < 0)
+               return zbc;
+
        priv->zbc_depth[zbc].format = format;
        priv->zbc_depth[zbc].ds = ds;
        priv->zbc_depth[zbc].l2 = l2;
index 4fc6ab12382d9774694e05d3e664014dc7650cc2..1794a05205d8cc5f6e9064e7e790c605ba9327f0 100644 (file)
@@ -14,7 +14,7 @@ struct nouveau_client {
        void *data;
 
        int (*ntfy)(const void *, u32, const void *, u32);
-       struct nvkm_client_notify *notify[8];
+       struct nvkm_client_notify *notify[16];
 };
 
 static inline struct nouveau_client *
index 73b1ed20c8d597b5d6b4c9f67f91b24cb3814d30..8bcbdf39cfb2db0844a5c030494096488cfc40e2 100644 (file)
@@ -99,8 +99,13 @@ nouveau_bar_alloc(struct nouveau_bar *bar, struct nouveau_object *parent,
                  struct nouveau_mem *mem, struct nouveau_object **pobject)
 {
        struct nouveau_object *engine = nv_object(bar);
-       return nouveau_object_ctor(parent, engine, &nouveau_barobj_oclass,
-                                  mem, 0, pobject);
+       int ret = -ENOMEM;
+       if (bar->iomem) {
+               ret = nouveau_object_ctor(parent, engine,
+                                         &nouveau_barobj_oclass,
+                                         mem, 0, pobject);
+       }
+       return ret;
 }
 
 int
@@ -118,9 +123,12 @@ nouveau_bar_create_(struct nouveau_object *parent,
        if (ret)
                return ret;
 
-       if (nv_device_resource_len(device, 3) != 0)
+       if (nv_device_resource_len(device, 3) != 0) {
                bar->iomem = ioremap(nv_device_resource_start(device, 3),
                                     nv_device_resource_len(device, 3));
+               if (!bar->iomem)
+                       nv_warn(bar, "PRAMIN ioremap failed\n");
+       }
 
        return 0;
 }
index 946518572346adf5d6cc0675c11552300308c8b2..2b284b19276330aabd6b584c55b21eb727232662 100644 (file)
@@ -554,13 +554,13 @@ nvc0_ram_create_(struct nouveau_object *parent, struct nouveau_object *engine,
        } else {
                /* otherwise, address lowest common amount from 0GiB */
                ret = nouveau_mm_init(&pfb->vram, rsvd_head,
-                                     (bsize << 8) * parts, 1);
+                                     (bsize << 8) * parts - rsvd_head, 1);
                if (ret)
                        return ret;
 
                /* and the rest starting from (8GiB + common_size) */
                offset = (0x0200000000ULL >> 12) + (bsize << 8);
-               length = (ram->size >> 12) - (bsize << 8) - rsvd_tail;
+               length = (ram->size >> 12) - ((bsize * parts) << 8) - rsvd_tail;
 
                ret = nouveau_mm_init(&pfb->vram, offset, length, 0);
                if (ret)
index 9e00a1ede1202c93ef2ba190d4a3bd5bc03b183d..b54b582e72c4764e040769718d6dca566f1bb840 100644 (file)
@@ -156,7 +156,7 @@ gf100_ltc_init_tag_ram(struct nouveau_fb *pfb, struct nvkm_ltc_priv *priv)
        if (ret) {
                priv->num_tags = 0;
        } else {
-               u64 tag_base = (priv->tag_ram->offset << 12) + tag_margin;
+               u64 tag_base = ((u64)priv->tag_ram->offset << 12) + tag_margin;
 
                tag_base += tag_align - 1;
                ret = do_div(tag_base, tag_align);
index da5d631aa5b9e34e618187e4474ba43e14474227..01da508625f27e4ad1c27393b8eaa928634564aa 100644 (file)
@@ -1228,7 +1228,6 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
        struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
        struct nouveau_drm *drm = nouveau_bdev(bdev);
        struct nouveau_mem *node = mem->mm_node;
-       struct drm_device *dev = drm->dev;
        int ret;
 
        mem->bus.addr = NULL;
@@ -1247,7 +1246,7 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
                if (drm->agp.stat == ENABLED) {
                        mem->bus.offset = mem->start << PAGE_SHIFT;
                        mem->bus.base = drm->agp.base;
-                       mem->bus.is_iomem = !dev->agp->cant_use_aperture;
+                       mem->bus.is_iomem = !drm->dev->agp->cant_use_aperture;
                }
 #endif
                if (drm->device.info.family < NV_DEVICE_INFO_V0_TESLA || !node->memtype)
index 1cc7b603c75342799835825708e0d6edb144f620..65b4fd53dd4e13186c2d33a072b380e2b8a1fdd1 100644 (file)
@@ -592,7 +592,9 @@ nouveau_display_repin(struct drm_device *dev)
                if (!nouveau_fb || !nouveau_fb->nvbo)
                        continue;
 
-               nouveau_bo_pin(nouveau_fb->nvbo, TTM_PL_FLAG_VRAM);
+               ret = nouveau_bo_pin(nouveau_fb->nvbo, TTM_PL_FLAG_VRAM);
+               if (ret)
+                       NV_ERROR(drm, "Could not pin framebuffer\n");
        }
 
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
index ebfe3180109e8e2bcf2f4a86bf5d7c80a3751e56..8bdd27091db8fd1aa7a34a3174b625c6a6d2a830 100644 (file)
@@ -226,7 +226,7 @@ nouveau_fbcon_accel_restore(struct drm_device *dev)
        }
 }
 
-void
+static void
 nouveau_fbcon_accel_fini(struct drm_device *dev)
 {
        struct nouveau_drm *drm = nouveau_drm(dev);
@@ -246,7 +246,7 @@ nouveau_fbcon_accel_fini(struct drm_device *dev)
        }
 }
 
-void
+static void
 nouveau_fbcon_accel_init(struct drm_device *dev)
 {
        struct nouveau_drm *drm = nouveau_drm(dev);
index 0ffeb50d008879feab8755083178bb11dca1e050..246a824c16ca9a88acc05c5f464a0d7a5f387a23 100644 (file)
@@ -149,7 +149,8 @@ power_down:
 static int nouveau_platform_remove(struct platform_device *pdev)
 {
        struct drm_device *drm_dev = platform_get_drvdata(pdev);
-       struct nouveau_device *device = nouveau_dev(drm_dev);
+       struct nouveau_drm *drm = nouveau_drm(drm_dev);
+       struct nouveau_device *device = nvkm_device(&drm->device);
        struct nouveau_platform_gpu *gpu = nv_device_to_platform(device)->gpu;
 
        nouveau_drm_device_remove(drm_dev);
index cc81e0e5fd30652203bc9f2af64db3055c71258d..573491f847921bfc6eec27245b370096664de122 100644 (file)
@@ -428,8 +428,8 @@ struct nv50_disp_dac_pwr_v0 {
 struct nv50_disp_dac_load_v0 {
        __u8  version;
        __u8  load;
-       __u16 data;
-       __u8  pad04[4];
+       __u8  pad02[2];
+       __u32 data;
 };
 
 struct nv50_disp_sor_pwr_v0 {
index 7c06123a559c56ddfa3dd45e30095869ec87a8a6..0898c3155292c54453df568921e546d59bb3db4f 100644 (file)
@@ -87,12 +87,25 @@ nvif_notify_get(struct nvif_notify *notify)
        return 0;
 }
 
+static inline int
+nvif_notify_func(struct nvif_notify *notify, bool keep)
+{
+       int ret = notify->func(notify);
+       if (ret == NVIF_NOTIFY_KEEP ||
+           !test_and_clear_bit(NVKM_NOTIFY_USER, &notify->flags)) {
+               if (!keep)
+                       atomic_dec(&notify->putcnt);
+               else
+                       nvif_notify_get_(notify);
+       }
+       return ret;
+}
+
 static void
 nvif_notify_work(struct work_struct *work)
 {
        struct nvif_notify *notify = container_of(work, typeof(*notify), work);
-       if (notify->func(notify) == NVIF_NOTIFY_KEEP)
-               nvif_notify_get_(notify);
+       nvif_notify_func(notify, true);
 }
 
 int
@@ -113,19 +126,15 @@ nvif_notify(const void *header, u32 length, const void *data, u32 size)
        if (!WARN_ON(notify == NULL)) {
                struct nvif_client *client = nvif_client(notify->object);
                if (!WARN_ON(notify->size != size)) {
+                       atomic_inc(&notify->putcnt);
                        if (test_bit(NVIF_NOTIFY_WORK, &notify->flags)) {
-                               atomic_inc(&notify->putcnt);
                                memcpy((void *)notify->data, data, size);
                                schedule_work(&notify->work);
                                return NVIF_NOTIFY_DROP;
                        }
                        notify->data = data;
-                       ret = notify->func(notify);
+                       ret = nvif_notify_func(notify, client->driver->keep);
                        notify->data = NULL;
-                       if (ret != NVIF_NOTIFY_DROP && client->driver->keep) {
-                               atomic_inc(&notify->putcnt);
-                               nvif_notify_get_(notify);
-                       }
                }
        }
 
@@ -228,8 +237,10 @@ nvif_notify_new(struct nvif_object *object, int (*func)(struct nvif_notify *),
        if (notify) {
                int ret = nvif_notify_init(object, nvif_notify_del, func, work,
                                           type, data, size, reply, notify);
-               if (ret)
+               if (ret) {
                        kfree(notify);
+                       notify = NULL;
+               }
                *pnotify = notify;
                return ret;
        }
index b0c82206ece204b649a2dad207b6faea405b05c6..dd85b56f6aa502a9ba65dcb9d9e9b2e61da7f664 100644 (file)
@@ -275,8 +275,10 @@ nvif_object_new(struct nvif_object *parent, u32 handle, u32 oclass,
        if (object) {
                int ret = nvif_object_init(parent, nvif_object_del, handle,
                                           oclass, data, size, object);
-               if (ret)
+               if (ret) {
                        kfree(object);
+                       object = NULL;
+               }
                *pobject = object;
                return ret;
        }
index 0013ad0db9efceea452959db8a3bfe12fc4440ee..f77b7135ee4cde8e07b96c619f0bca8f94cdc37b 100644 (file)
@@ -76,7 +76,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
        evergreen.o evergreen_cs.o evergreen_blit_shaders.o \
        evergreen_hdmi.o radeon_trace_points.o ni.o cayman_blit_shaders.o \
        atombios_encoders.o radeon_semaphore.o radeon_sa.o atombios_i2c.o si.o \
-       si_blit_shaders.o radeon_prime.o radeon_uvd.o cik.o cik_blit_shaders.o \
+       si_blit_shaders.o radeon_prime.o cik.o cik_blit_shaders.o \
        r600_dpm.o rs780_dpm.o rv6xx_dpm.o rv770_dpm.o rv730_dpm.o rv740_dpm.o \
        rv770_smc.o cypress_dpm.o btc_dpm.o sumo_dpm.o sumo_smc.o trinity_dpm.o \
        trinity_smc.o ni_dpm.o si_smc.o si_dpm.o kv_smc.o kv_dpm.o ci_smc.o \
index 022561e2870722bd56c22fa65ebaf5b9bf1987a8..d416bb2ff48dae0376b15e4789652799ff0638c3 100644 (file)
@@ -869,6 +869,9 @@ static int ci_set_thermal_temperature_range(struct radeon_device *rdev,
        WREG32_SMC(CG_THERMAL_CTRL, tmp);
 #endif
 
+       rdev->pm.dpm.thermal.min_temp = low_temp;
+       rdev->pm.dpm.thermal.max_temp = high_temp;
+
        return 0;
 }
 
index b625646bf3e242c11d21fd268c698a502604fae0..fa9565957f9d4516ab801e645b5ac2153db535ad 100644 (file)
@@ -3483,7 +3483,7 @@ static void cik_gpu_init(struct radeon_device *rdev)
        u32 mc_shared_chmap, mc_arb_ramcfg;
        u32 hdp_host_path_cntl;
        u32 tmp;
-       int i, j, k;
+       int i, j;
 
        switch (rdev->family) {
        case CHIP_BONAIRE:
@@ -3544,6 +3544,7 @@ static void cik_gpu_init(struct radeon_device *rdev)
                           (rdev->pdev->device == 0x130B) ||
                           (rdev->pdev->device == 0x130E) ||
                           (rdev->pdev->device == 0x1315) ||
+                          (rdev->pdev->device == 0x1318) ||
                           (rdev->pdev->device == 0x131B)) {
                        rdev->config.cik.max_cu_per_sh = 4;
                        rdev->config.cik.max_backends_per_se = 1;
@@ -3672,12 +3673,11 @@ static void cik_gpu_init(struct radeon_device *rdev)
                     rdev->config.cik.max_sh_per_se,
                     rdev->config.cik.max_backends_per_se);
 
+       rdev->config.cik.active_cus = 0;
        for (i = 0; i < rdev->config.cik.max_shader_engines; i++) {
                for (j = 0; j < rdev->config.cik.max_sh_per_se; j++) {
-                       for (k = 0; k < rdev->config.cik.max_cu_per_sh; k++) {
-                               rdev->config.cik.active_cus +=
-                                       hweight32(cik_get_cu_active_bitmap(rdev, i, j));
-                       }
+                       rdev->config.cik.active_cus +=
+                               hweight32(cik_get_cu_active_bitmap(rdev, i, j));
                }
        }
 
@@ -3801,7 +3801,7 @@ int cik_ring_test(struct radeon_device *rdev, struct radeon_ring *ring)
        radeon_ring_write(ring, PACKET3(PACKET3_SET_UCONFIG_REG, 1));
        radeon_ring_write(ring, ((scratch - PACKET3_SET_UCONFIG_REG_START) >> 2));
        radeon_ring_write(ring, 0xDEADBEEF);
-       radeon_ring_unlock_commit(rdev, ring);
+       radeon_ring_unlock_commit(rdev, ring, false);
 
        for (i = 0; i < rdev->usec_timeout; i++) {
                tmp = RREG32(scratch);
@@ -3920,6 +3920,17 @@ void cik_fence_compute_ring_emit(struct radeon_device *rdev,
        radeon_ring_write(ring, 0);
 }
 
+/**
+ * cik_semaphore_ring_emit - emit a semaphore on the CP ring
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon ring buffer object
+ * @semaphore: radeon semaphore object
+ * @emit_wait: Is this a sempahore wait?
+ *
+ * Emits a semaphore signal/wait packet to the CP ring and prevents the PFP
+ * from running ahead of semaphore waits.
+ */
 bool cik_semaphore_ring_emit(struct radeon_device *rdev,
                             struct radeon_ring *ring,
                             struct radeon_semaphore *semaphore,
@@ -3932,6 +3943,12 @@ bool cik_semaphore_ring_emit(struct radeon_device *rdev,
        radeon_ring_write(ring, lower_32_bits(addr));
        radeon_ring_write(ring, (upper_32_bits(addr) & 0xffff) | sel);
 
+       if (emit_wait && ring->idx == RADEON_RING_TYPE_GFX_INDEX) {
+               /* Prevent the PFP from running ahead of the semaphore wait */
+               radeon_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0));
+               radeon_ring_write(ring, 0x0);
+       }
+
        return true;
 }
 
@@ -4004,7 +4021,7 @@ int cik_copy_cpdma(struct radeon_device *rdev,
                return r;
        }
 
-       radeon_ring_unlock_commit(rdev, ring);
+       radeon_ring_unlock_commit(rdev, ring, false);
        radeon_semaphore_free(rdev, &sem, *fence);
 
        return r;
@@ -4103,7 +4120,7 @@ int cik_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
        ib.ptr[1] = ((scratch - PACKET3_SET_UCONFIG_REG_START) >> 2);
        ib.ptr[2] = 0xDEADBEEF;
        ib.length_dw = 3;
-       r = radeon_ib_schedule(rdev, &ib, NULL);
+       r = radeon_ib_schedule(rdev, &ib, NULL, false);
        if (r) {
                radeon_scratch_free(rdev, scratch);
                radeon_ib_free(rdev, &ib);
@@ -4324,7 +4341,7 @@ static int cik_cp_gfx_start(struct radeon_device *rdev)
        radeon_ring_write(ring, 0x0000000e); /* VGT_VERTEX_REUSE_BLOCK_CNTL */
        radeon_ring_write(ring, 0x00000010); /* VGT_OUT_DEALLOC_CNTL */
 
-       radeon_ring_unlock_commit(rdev, ring);
+       radeon_ring_unlock_commit(rdev, ring, false);
 
        return 0;
 }
@@ -5732,20 +5749,17 @@ static int cik_pcie_gart_enable(struct radeon_device *rdev)
        WREG32(0x15D8, 0);
        WREG32(0x15DC, 0);
 
-       /* empty context1-15 */
-       /* FIXME start with 4G, once using 2 level pt switch to full
-        * vm size space
-        */
+       /* restore context1-15 */
        /* set vm size, must be a multiple of 4 */
        WREG32(VM_CONTEXT1_PAGE_TABLE_START_ADDR, 0);
        WREG32(VM_CONTEXT1_PAGE_TABLE_END_ADDR, rdev->vm_manager.max_pfn);
        for (i = 1; i < 16; i++) {
                if (i < 8)
                        WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (i << 2),
-                              rdev->gart.table_addr >> 12);
+                              rdev->vm_manager.saved_table_addr[i]);
                else
                        WREG32(VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((i - 8) << 2),
-                              rdev->gart.table_addr >> 12);
+                              rdev->vm_manager.saved_table_addr[i]);
        }
 
        /* enable context1-15 */
@@ -5810,6 +5824,17 @@ static int cik_pcie_gart_enable(struct radeon_device *rdev)
  */
 static void cik_pcie_gart_disable(struct radeon_device *rdev)
 {
+       unsigned i;
+
+       for (i = 1; i < 16; ++i) {
+               uint32_t reg;
+               if (i < 8)
+                       reg = VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (i << 2);
+               else
+                       reg = VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((i - 8) << 2);
+               rdev->vm_manager.saved_table_addr[i] = RREG32(reg);
+       }
+
        /* Disable all tables */
        WREG32(VM_CONTEXT0_CNTL, 0);
        WREG32(VM_CONTEXT1_CNTL, 0);
@@ -5958,14 +5983,14 @@ void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
 
        /* update SH_MEM_* regs */
        radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
-       radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
+       radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(usepfp) |
                                 WRITE_DATA_DST_SEL(0)));
        radeon_ring_write(ring, SRBM_GFX_CNTL >> 2);
        radeon_ring_write(ring, 0);
        radeon_ring_write(ring, VMID(vm->id));
 
        radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 6));
-       radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
+       radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(usepfp) |
                                 WRITE_DATA_DST_SEL(0)));
        radeon_ring_write(ring, SH_MEM_BASES >> 2);
        radeon_ring_write(ring, 0);
@@ -5976,7 +6001,7 @@ void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
        radeon_ring_write(ring, 0); /* SH_MEM_APE1_LIMIT */
 
        radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
-       radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
+       radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(usepfp) |
                                 WRITE_DATA_DST_SEL(0)));
        radeon_ring_write(ring, SRBM_GFX_CNTL >> 2);
        radeon_ring_write(ring, 0);
@@ -5987,7 +6012,7 @@ void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
 
        /* bits 0-15 are the VM contexts0-15 */
        radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
-       radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
+       radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(usepfp) |
                                 WRITE_DATA_DST_SEL(0)));
        radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2);
        radeon_ring_write(ring, 0);
@@ -9538,6 +9563,9 @@ static void cik_pcie_gen3_enable(struct radeon_device *rdev)
        int ret, i;
        u16 tmp16;
 
+       if (pci_is_root_bus(rdev->pdev->bus))
+               return;
+
        if (radeon_pcie_gen2 == 0)
                return;
 
@@ -9764,7 +9792,8 @@ static void cik_program_aspm(struct radeon_device *rdev)
                        if (orig != data)
                                WREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL, data);
 
-                       if (!disable_clkreq) {
+                       if (!disable_clkreq &&
+                           !pci_is_root_bus(rdev->pdev->bus)) {
                                struct pci_dev *root = rdev->pdev->bus->self;
                                u32 lnkcap;
 
index bcf480510ac228af4bdf6e177eb0ccfb5951b24c..192278bc993ce581e42b9eb2e47a207533a45cd5 100644 (file)
@@ -596,7 +596,7 @@ int cik_copy_dma(struct radeon_device *rdev,
                return r;
        }
 
-       radeon_ring_unlock_commit(rdev, ring);
+       radeon_ring_unlock_commit(rdev, ring, false);
        radeon_semaphore_free(rdev, &sem, *fence);
 
        return r;
@@ -638,7 +638,7 @@ int cik_sdma_ring_test(struct radeon_device *rdev,
        radeon_ring_write(ring, upper_32_bits(rdev->vram_scratch.gpu_addr));
        radeon_ring_write(ring, 1); /* number of DWs to follow */
        radeon_ring_write(ring, 0xDEADBEEF);
-       radeon_ring_unlock_commit(rdev, ring);
+       radeon_ring_unlock_commit(rdev, ring, false);
 
        for (i = 0; i < rdev->usec_timeout; i++) {
                tmp = readl(ptr);
@@ -695,7 +695,7 @@ int cik_sdma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
        ib.ptr[4] = 0xDEADBEEF;
        ib.length_dw = 5;
 
-       r = radeon_ib_schedule(rdev, &ib, NULL);
+       r = radeon_ib_schedule(rdev, &ib, NULL, false);
        if (r) {
                radeon_ib_free(rdev, &ib);
                DRM_ERROR("radeon: failed to schedule ib (%d).\n", r);
index 4fedd14e670aeb33e07fadcf5ff2564c2cc2681c..dbca60c7d097664e381d9bd5c6539d140aa72c16 100644 (file)
@@ -2869,7 +2869,7 @@ static int evergreen_cp_start(struct radeon_device *rdev)
        radeon_ring_write(ring, PACKET3_ME_INITIALIZE_DEVICE_ID(1));
        radeon_ring_write(ring, 0);
        radeon_ring_write(ring, 0);
-       radeon_ring_unlock_commit(rdev, ring);
+       radeon_ring_unlock_commit(rdev, ring, false);
 
        cp_me = 0xff;
        WREG32(CP_ME_CNTL, cp_me);
@@ -2912,7 +2912,7 @@ static int evergreen_cp_start(struct radeon_device *rdev)
        radeon_ring_write(ring, 0x0000000e); /* VGT_VERTEX_REUSE_BLOCK_CNTL */
        radeon_ring_write(ring, 0x00000010); /*  */
 
-       radeon_ring_unlock_commit(rdev, ring);
+       radeon_ring_unlock_commit(rdev, ring, false);
 
        return 0;
 }
index 478caefe0fef918011fadd78e1419ac92183ae54..afaba388c36dec2fcd6cd5b986a9ab4d70406385 100644 (file)
@@ -155,7 +155,7 @@ int evergreen_copy_dma(struct radeon_device *rdev,
                return r;
        }
 
-       radeon_ring_unlock_commit(rdev, ring);
+       radeon_ring_unlock_commit(rdev, ring, false);
        radeon_semaphore_free(rdev, &sem, *fence);
 
        return r;
index 9ef8c38f2d6622c25a5b3e1e43a37064c8cf1776..8b58e11b64fa5a13611941b3aca6b04d2c1600a0 100644 (file)
@@ -1438,14 +1438,14 @@ static int kv_update_uvd_dpm(struct radeon_device *rdev, bool gate)
        return kv_enable_uvd_dpm(rdev, !gate);
 }
 
-static u8 kv_get_vce_boot_level(struct radeon_device *rdev)
+static u8 kv_get_vce_boot_level(struct radeon_device *rdev, u32 evclk)
 {
        u8 i;
        struct radeon_vce_clock_voltage_dependency_table *table =
                &rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table;
 
        for (i = 0; i < table->count; i++) {
-               if (table->entries[i].evclk >= 0) /* XXX */
+               if (table->entries[i].evclk >= evclk)
                        break;
        }
 
@@ -1468,7 +1468,7 @@ static int kv_update_vce_dpm(struct radeon_device *rdev,
                if (pi->caps_stable_p_state)
                        pi->vce_boot_level = table->count - 1;
                else
-                       pi->vce_boot_level = kv_get_vce_boot_level(rdev);
+                       pi->vce_boot_level = kv_get_vce_boot_level(rdev, radeon_new_state->evclk);
 
                ret = kv_copy_bytes_to_smc(rdev,
                                           pi->dpm_table_start +
@@ -2726,7 +2726,10 @@ int kv_dpm_init(struct radeon_device *rdev)
        pi->caps_sclk_ds = true;
        pi->enable_auto_thermal_throttling = true;
        pi->disable_nb_ps3_in_battery = false;
-       pi->bapm_enable = true;
+       if (radeon_bapm == 0)
+               pi->bapm_enable = false;
+       else
+               pi->bapm_enable = true;
        pi->voltage_drop_t = 0;
        pi->caps_sclk_throttle_low_notification = false;
        pi->caps_fps = false; /* true? */
index 327b85f7fd0d45eb434a8f8232a206ac736ab0be..3faee58946dd0027b67d5d835af50f8de899ec93 100644 (file)
@@ -1271,7 +1271,7 @@ static int cayman_pcie_gart_enable(struct radeon_device *rdev)
                WREG32(VM_CONTEXT0_PAGE_TABLE_START_ADDR + (i << 2), 0);
                WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR + (i << 2), rdev->vm_manager.max_pfn);
                WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (i << 2),
-                       rdev->gart.table_addr >> 12);
+                      rdev->vm_manager.saved_table_addr[i]);
        }
 
        /* enable context1-7 */
@@ -1303,6 +1303,13 @@ static int cayman_pcie_gart_enable(struct radeon_device *rdev)
 
 static void cayman_pcie_gart_disable(struct radeon_device *rdev)
 {
+       unsigned i;
+
+       for (i = 1; i < 8; ++i) {
+               rdev->vm_manager.saved_table_addr[i] = RREG32(
+                       VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (i << 2));
+       }
+
        /* Disable all tables */
        WREG32(VM_CONTEXT0_CNTL, 0);
        WREG32(VM_CONTEXT1_CNTL, 0);
@@ -1505,7 +1512,7 @@ static int cayman_cp_start(struct radeon_device *rdev)
        radeon_ring_write(ring, PACKET3_ME_INITIALIZE_DEVICE_ID(1));
        radeon_ring_write(ring, 0);
        radeon_ring_write(ring, 0);
-       radeon_ring_unlock_commit(rdev, ring);
+       radeon_ring_unlock_commit(rdev, ring, false);
 
        cayman_cp_enable(rdev, true);
 
@@ -1547,7 +1554,7 @@ static int cayman_cp_start(struct radeon_device *rdev)
        radeon_ring_write(ring, 0x0000000e); /* VGT_VERTEX_REUSE_BLOCK_CNTL */
        radeon_ring_write(ring, 0x00000010); /*  */
 
-       radeon_ring_unlock_commit(rdev, ring);
+       radeon_ring_unlock_commit(rdev, ring, false);
 
        /* XXX init other rings */
 
index 04b5940b89234893f3f3042e5a00f30f97e899cf..4c5ec44ff328b3c63203e4c7c92f5283126e65e9 100644 (file)
@@ -925,7 +925,7 @@ int r100_copy_blit(struct radeon_device *rdev,
        if (fence) {
                r = radeon_fence_emit(rdev, fence, RADEON_RING_TYPE_GFX_INDEX);
        }
-       radeon_ring_unlock_commit(rdev, ring);
+       radeon_ring_unlock_commit(rdev, ring, false);
        return r;
 }
 
@@ -958,7 +958,7 @@ void r100_ring_start(struct radeon_device *rdev, struct radeon_ring *ring)
                          RADEON_ISYNC_ANY3D_IDLE2D |
                          RADEON_ISYNC_WAIT_IDLEGUI |
                          RADEON_ISYNC_CPSCRATCH_IDLEGUI);
-       radeon_ring_unlock_commit(rdev, ring);
+       radeon_ring_unlock_commit(rdev, ring, false);
 }
 
 
@@ -3638,7 +3638,7 @@ int r100_ring_test(struct radeon_device *rdev, struct radeon_ring *ring)
        }
        radeon_ring_write(ring, PACKET0(scratch, 0));
        radeon_ring_write(ring, 0xDEADBEEF);
-       radeon_ring_unlock_commit(rdev, ring);
+       radeon_ring_unlock_commit(rdev, ring, false);
        for (i = 0; i < rdev->usec_timeout; i++) {
                tmp = RREG32(scratch);
                if (tmp == 0xDEADBEEF) {
@@ -3700,7 +3700,7 @@ int r100_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
        ib.ptr[6] = PACKET2(0);
        ib.ptr[7] = PACKET2(0);
        ib.length_dw = 8;
-       r = radeon_ib_schedule(rdev, &ib, NULL);
+       r = radeon_ib_schedule(rdev, &ib, NULL, false);
        if (r) {
                DRM_ERROR("radeon: failed to schedule ib (%d).\n", r);
                goto free_ib;
index 58f0473aa73fba3cd1e62a786d6776c7a20ccd3b..67780374a65203fc57736510685f917b14d4ce89 100644 (file)
@@ -121,7 +121,7 @@ int r200_copy_dma(struct radeon_device *rdev,
        if (fence) {
                r = radeon_fence_emit(rdev, fence, RADEON_RING_TYPE_GFX_INDEX);
        }
-       radeon_ring_unlock_commit(rdev, ring);
+       radeon_ring_unlock_commit(rdev, ring, false);
        return r;
 }
 
index 75b30338c226f01ef263edcac893e16dec496643..1bc4704034ce9d90f9563f598bb6135b44878f06 100644 (file)
@@ -295,7 +295,7 @@ void r300_ring_start(struct radeon_device *rdev, struct radeon_ring *ring)
        radeon_ring_write(ring,
                          R300_GEOMETRY_ROUND_NEAREST |
                          R300_COLOR_ROUND_NEAREST);
-       radeon_ring_unlock_commit(rdev, ring);
+       radeon_ring_unlock_commit(rdev, ring, false);
 }
 
 static void r300_errata(struct radeon_device *rdev)
index 802b19220a21358712dc304a894db892ec3537fb..2828605aef3fcdeb76b529e7b478bdc866d1a27f 100644 (file)
@@ -219,7 +219,7 @@ static void r420_cp_errata_init(struct radeon_device *rdev)
        radeon_ring_write(ring, PACKET0(R300_CP_RESYNC_ADDR, 1));
        radeon_ring_write(ring, rdev->config.r300.resync_scratch);
        radeon_ring_write(ring, 0xDEADBEEF);
-       radeon_ring_unlock_commit(rdev, ring);
+       radeon_ring_unlock_commit(rdev, ring, false);
 }
 
 static void r420_cp_errata_fini(struct radeon_device *rdev)
@@ -232,7 +232,7 @@ static void r420_cp_errata_fini(struct radeon_device *rdev)
        radeon_ring_lock(rdev, ring, 8);
        radeon_ring_write(ring, PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0));
        radeon_ring_write(ring, R300_RB3D_DC_FINISH);
-       radeon_ring_unlock_commit(rdev, ring);
+       radeon_ring_unlock_commit(rdev, ring, false);
        radeon_scratch_free(rdev, rdev->config.r300.resync_scratch);
 }
 
index c70a504d96af5a8ac6f8a9f8e40dd2039917e467..e616eb5f6e7a4076979650147acad69b9b40d567 100644 (file)
@@ -1812,7 +1812,6 @@ static void r600_gpu_init(struct radeon_device *rdev)
 {
        u32 tiling_config;
        u32 ramcfg;
-       u32 cc_rb_backend_disable;
        u32 cc_gc_shader_pipe_config;
        u32 tmp;
        int i, j;
@@ -1939,29 +1938,20 @@ static void r600_gpu_init(struct radeon_device *rdev)
        }
        tiling_config |= BANK_SWAPS(1);
 
-       cc_rb_backend_disable = RREG32(CC_RB_BACKEND_DISABLE) & 0x00ff0000;
-       tmp = R6XX_MAX_BACKENDS -
-               r600_count_pipe_bits((cc_rb_backend_disable >> 16) & R6XX_MAX_BACKENDS_MASK);
-       if (tmp < rdev->config.r600.max_backends) {
-               rdev->config.r600.max_backends = tmp;
-       }
-
        cc_gc_shader_pipe_config = RREG32(CC_GC_SHADER_PIPE_CONFIG) & 0x00ffff00;
-       tmp = R6XX_MAX_PIPES -
-               r600_count_pipe_bits((cc_gc_shader_pipe_config >> 8) & R6XX_MAX_PIPES_MASK);
-       if (tmp < rdev->config.r600.max_pipes) {
-               rdev->config.r600.max_pipes = tmp;
-       }
-       tmp = R6XX_MAX_SIMDS -
-               r600_count_pipe_bits((cc_gc_shader_pipe_config >> 16) & R6XX_MAX_SIMDS_MASK);
-       if (tmp < rdev->config.r600.max_simds) {
-               rdev->config.r600.max_simds = tmp;
-       }
        tmp = rdev->config.r600.max_simds -
                r600_count_pipe_bits((cc_gc_shader_pipe_config >> 16) & R6XX_MAX_SIMDS_MASK);
        rdev->config.r600.active_simds = tmp;
 
        disabled_rb_mask = (RREG32(CC_RB_BACKEND_DISABLE) >> 16) & R6XX_MAX_BACKENDS_MASK;
+       tmp = 0;
+       for (i = 0; i < rdev->config.r600.max_backends; i++)
+               tmp |= (1 << i);
+       /* if all the backends are disabled, fix it up here */
+       if ((disabled_rb_mask & tmp) == tmp) {
+               for (i = 0; i < rdev->config.r600.max_backends; i++)
+                       disabled_rb_mask &= ~(1 << i);
+       }
        tmp = (tiling_config & PIPE_TILING__MASK) >> PIPE_TILING__SHIFT;
        tmp = r6xx_remap_render_backend(rdev, tmp, rdev->config.r600.max_backends,
                                        R6XX_MAX_BACKENDS, disabled_rb_mask);
@@ -2547,7 +2537,7 @@ int r600_cp_start(struct radeon_device *rdev)
        radeon_ring_write(ring, PACKET3_ME_INITIALIZE_DEVICE_ID(1));
        radeon_ring_write(ring, 0);
        radeon_ring_write(ring, 0);
-       radeon_ring_unlock_commit(rdev, ring);
+       radeon_ring_unlock_commit(rdev, ring, false);
 
        cp_me = 0xff;
        WREG32(R_0086D8_CP_ME_CNTL, cp_me);
@@ -2683,7 +2673,7 @@ int r600_ring_test(struct radeon_device *rdev, struct radeon_ring *ring)
        radeon_ring_write(ring, PACKET3(PACKET3_SET_CONFIG_REG, 1));
        radeon_ring_write(ring, ((scratch - PACKET3_SET_CONFIG_REG_OFFSET) >> 2));
        radeon_ring_write(ring, 0xDEADBEEF);
-       radeon_ring_unlock_commit(rdev, ring);
+       radeon_ring_unlock_commit(rdev, ring, false);
        for (i = 0; i < rdev->usec_timeout; i++) {
                tmp = RREG32(scratch);
                if (tmp == 0xDEADBEEF)
@@ -2753,6 +2743,17 @@ void r600_fence_ring_emit(struct radeon_device *rdev,
        }
 }
 
+/**
+ * r600_semaphore_ring_emit - emit a semaphore on the CP ring
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon ring buffer object
+ * @semaphore: radeon semaphore object
+ * @emit_wait: Is this a sempahore wait?
+ *
+ * Emits a semaphore signal/wait packet to the CP ring and prevents the PFP
+ * from running ahead of semaphore waits.
+ */
 bool r600_semaphore_ring_emit(struct radeon_device *rdev,
                              struct radeon_ring *ring,
                              struct radeon_semaphore *semaphore,
@@ -2768,6 +2769,13 @@ bool r600_semaphore_ring_emit(struct radeon_device *rdev,
        radeon_ring_write(ring, lower_32_bits(addr));
        radeon_ring_write(ring, (upper_32_bits(addr) & 0xff) | sel);
 
+       /* PFP_SYNC_ME packet only exists on 7xx+ */
+       if (emit_wait && (rdev->family >= CHIP_RV770)) {
+               /* Prevent the PFP from running ahead of the semaphore wait */
+               radeon_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0));
+               radeon_ring_write(ring, 0x0);
+       }
+
        return true;
 }
 
@@ -2845,7 +2853,7 @@ int r600_copy_cpdma(struct radeon_device *rdev,
                return r;
        }
 
-       radeon_ring_unlock_commit(rdev, ring);
+       radeon_ring_unlock_commit(rdev, ring, false);
        radeon_semaphore_free(rdev, &sem, *fence);
 
        return r;
@@ -3165,7 +3173,7 @@ int r600_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
        ib.ptr[1] = ((scratch - PACKET3_SET_CONFIG_REG_OFFSET) >> 2);
        ib.ptr[2] = 0xDEADBEEF;
        ib.length_dw = 3;
-       r = radeon_ib_schedule(rdev, &ib, NULL);
+       r = radeon_ib_schedule(rdev, &ib, NULL, false);
        if (r) {
                DRM_ERROR("radeon: failed to schedule ib (%d).\n", r);
                goto free_ib;
index 4969cef44a1911b706e933fb8252397ddd893785..51fd98553eaf6c4a34e73c5baeecf95b94220e29 100644 (file)
@@ -261,7 +261,7 @@ int r600_dma_ring_test(struct radeon_device *rdev,
        radeon_ring_write(ring, rdev->vram_scratch.gpu_addr & 0xfffffffc);
        radeon_ring_write(ring, upper_32_bits(rdev->vram_scratch.gpu_addr) & 0xff);
        radeon_ring_write(ring, 0xDEADBEEF);
-       radeon_ring_unlock_commit(rdev, ring);
+       radeon_ring_unlock_commit(rdev, ring, false);
 
        for (i = 0; i < rdev->usec_timeout; i++) {
                tmp = readl(ptr);
@@ -368,7 +368,7 @@ int r600_dma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
        ib.ptr[3] = 0xDEADBEEF;
        ib.length_dw = 4;
 
-       r = radeon_ib_schedule(rdev, &ib, NULL);
+       r = radeon_ib_schedule(rdev, &ib, NULL, false);
        if (r) {
                radeon_ib_free(rdev, &ib);
                DRM_ERROR("radeon: failed to schedule ib (%d).\n", r);
@@ -493,7 +493,7 @@ int r600_copy_dma(struct radeon_device *rdev,
                return r;
        }
 
-       radeon_ring_unlock_commit(rdev, ring);
+       radeon_ring_unlock_commit(rdev, ring, false);
        radeon_semaphore_free(rdev, &sem, *fence);
 
        return r;
index f94e7a9afe754c602e5e40ddf600f7bef73add6e..0c4a7d8d93e0465e9f2d094fe127f283602b3239 100644 (file)
                 */
 #              define PACKET3_CP_DMA_CMD_SAIC      (1 << 28)
 #              define PACKET3_CP_DMA_CMD_DAIC      (1 << 29)
+#define        PACKET3_PFP_SYNC_ME                             0x42 /* r7xx+ only */
 #define        PACKET3_SURFACE_SYNC                            0x43
 #              define PACKET3_CB0_DEST_BASE_ENA    (1 << 6)
 #              define PACKET3_FULL_CACHE_ENA       (1 << 20) /* r7xx+ only */
index 9e1732eb402c5ec831c9bbd514084e7ce30462c2..5f05b4c8433807bf26a1b0ef80fd31a2c25d9a36 100644 (file)
@@ -105,6 +105,7 @@ extern int radeon_vm_size;
 extern int radeon_vm_block_size;
 extern int radeon_deep_color;
 extern int radeon_use_pflipirq;
+extern int radeon_bapm;
 
 /*
  * Copy from radeon_drv.h so we don't have to include both and have conflicting
@@ -914,6 +915,8 @@ struct radeon_vm_manager {
        u64                             vram_base_offset;
        /* is vm enabled? */
        bool                            enabled;
+       /* for hw to save the PD addr on suspend/resume */
+       uint32_t                        saved_table_addr[RADEON_NUM_VM];
 };
 
 /*
@@ -967,7 +970,7 @@ int radeon_ib_get(struct radeon_device *rdev, int ring,
                  unsigned size);
 void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib *ib);
 int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib,
-                      struct radeon_ib *const_ib);
+                      struct radeon_ib *const_ib, bool hdp_flush);
 int radeon_ib_pool_init(struct radeon_device *rdev);
 void radeon_ib_pool_fini(struct radeon_device *rdev);
 int radeon_ib_ring_tests(struct radeon_device *rdev);
@@ -977,8 +980,10 @@ bool radeon_ring_supports_scratch_reg(struct radeon_device *rdev,
 void radeon_ring_free_size(struct radeon_device *rdev, struct radeon_ring *cp);
 int radeon_ring_alloc(struct radeon_device *rdev, struct radeon_ring *cp, unsigned ndw);
 int radeon_ring_lock(struct radeon_device *rdev, struct radeon_ring *cp, unsigned ndw);
-void radeon_ring_commit(struct radeon_device *rdev, struct radeon_ring *cp);
-void radeon_ring_unlock_commit(struct radeon_device *rdev, struct radeon_ring *cp);
+void radeon_ring_commit(struct radeon_device *rdev, struct radeon_ring *cp,
+                       bool hdp_flush);
+void radeon_ring_unlock_commit(struct radeon_device *rdev, struct radeon_ring *cp,
+                              bool hdp_flush);
 void radeon_ring_undo(struct radeon_ring *ring);
 void radeon_ring_unlock_undo(struct radeon_device *rdev, struct radeon_ring *cp);
 int radeon_ring_test(struct radeon_device *rdev, struct radeon_ring *cp);
index ee712c199b2573f5978e1a254094e35f11090af0..83f382e8e40e35cb380d4fc6fd835a7ddac9c01a 100644 (file)
@@ -132,7 +132,8 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
                 * the buffers used for read only, which doubles the range
                 * to 0 to 31. 32 is reserved for the kernel driver.
                 */
-               priority = (r->flags & 0xf) * 2 + !!r->write_domain;
+               priority = (r->flags & RADEON_RELOC_PRIO_MASK) * 2
+                          + !!r->write_domain;
 
                /* the first reloc of an UVD job is the msg and that must be in
                   VRAM, also but everything into VRAM on AGP cards to avoid
@@ -450,7 +451,7 @@ static int radeon_cs_ib_chunk(struct radeon_device *rdev,
                radeon_vce_note_usage(rdev);
 
        radeon_cs_sync_rings(parser);
-       r = radeon_ib_schedule(rdev, &parser->ib, NULL);
+       r = radeon_ib_schedule(rdev, &parser->ib, NULL, true);
        if (r) {
                DRM_ERROR("Failed to schedule IB !\n");
        }
@@ -541,9 +542,9 @@ static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev,
 
        if ((rdev->family >= CHIP_TAHITI) &&
            (parser->chunk_const_ib_idx != -1)) {
-               r = radeon_ib_schedule(rdev, &parser->ib, &parser->const_ib);
+               r = radeon_ib_schedule(rdev, &parser->ib, &parser->const_ib, true);
        } else {
-               r = radeon_ib_schedule(rdev, &parser->ib, NULL);
+               r = radeon_ib_schedule(rdev, &parser->ib, NULL, true);
        }
 
 out:
index c8ea050c8fa463b8ae5fa6768a5cf67cc924f119..6a219bcee66d2d8a5d7b8bf49f2344584a0a36fd 100644 (file)
@@ -1680,8 +1680,8 @@ int radeon_gpu_reset(struct radeon_device *rdev)
        radeon_save_bios_scratch_regs(rdev);
        /* block TTM */
        resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev);
-       radeon_pm_suspend(rdev);
        radeon_suspend(rdev);
+       radeon_hpd_fini(rdev);
 
        for (i = 0; i < RADEON_NUM_RINGS; ++i) {
                ring_sizes[i] = radeon_ring_backup(rdev, &rdev->ring[i],
@@ -1726,9 +1726,39 @@ retry:
                }
        }
 
-       radeon_pm_resume(rdev);
+       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);
+       }
+
+       /* init dig PHYs, disp eng pll */
+       if (rdev->is_atom_bios) {
+               radeon_atom_encoder_init(rdev);
+               radeon_atom_disp_eng_pll_init(rdev);
+               /* turn on the BL */
+               if (rdev->mode_info.bl_encoder) {
+                       u8 bl_level = radeon_get_backlight_level(rdev,
+                                                                rdev->mode_info.bl_encoder);
+                       radeon_set_backlight_level(rdev, rdev->mode_info.bl_encoder,
+                                                  bl_level);
+               }
+       }
+       /* reset hpd state */
+       radeon_hpd_init(rdev);
+
        drm_helper_resume_force_mode(rdev->ddev);
 
+       /* set the power state here in case we are a PX system or headless */
+       if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled)
+               radeon_pm_compute_clocks(rdev);
+
        ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched);
        if (r) {
                /* bad news, how to tell it to userspace ? */
index 092d067f93e16534aca712779ce2aa5705069395..8df888908833f5d1a3e8d9f745edb5fe9b6143ea 100644 (file)
@@ -180,6 +180,7 @@ int radeon_vm_size = 8;
 int radeon_vm_block_size = -1;
 int radeon_deep_color = 0;
 int radeon_use_pflipirq = 2;
+int radeon_bapm = -1;
 
 MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers");
 module_param_named(no_wb, radeon_no_wb, int, 0444);
@@ -259,6 +260,9 @@ module_param_named(deep_color, radeon_deep_color, int, 0444);
 MODULE_PARM_DESC(use_pflipirq, "Pflip irqs for pageflip completion (0 = disable, 1 = as fallback, 2 = exclusive (default))");
 module_param_named(use_pflipirq, radeon_use_pflipirq, int, 0444);
 
+MODULE_PARM_DESC(bapm, "BAPM support (1 = enable, 0 = disable, -1 = auto)");
+module_param_named(bapm, radeon_bapm, int, 0444);
+
 static struct pci_device_id pciidlist[] = {
        radeon_PCI_IDS
 };
index 65b0c213488dcf084e08c2ddf95c92c28f367c83..5bf2c0a05827f57b459ca1be85e268af0bbf32ce 100644 (file)
@@ -107,6 +107,7 @@ void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib *ib)
  * @rdev: radeon_device pointer
  * @ib: IB object to schedule
  * @const_ib: Const IB to schedule (SI only)
+ * @hdp_flush: Whether or not to perform an HDP cache flush
  *
  * Schedule an IB on the associated ring (all asics).
  * Returns 0 on success, error on failure.
@@ -122,7 +123,7 @@ void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib *ib)
  * to SI there was just a DE IB.
  */
 int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib,
-                      struct radeon_ib *const_ib)
+                      struct radeon_ib *const_ib, bool hdp_flush)
 {
        struct radeon_ring *ring = &rdev->ring[ib->ring];
        int r = 0;
@@ -176,7 +177,7 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib,
        if (ib->vm)
                radeon_vm_fence(rdev, ib->vm, ib->fence);
 
-       radeon_ring_unlock_commit(rdev, ring);
+       radeon_ring_unlock_commit(rdev, ring, hdp_flush);
        return 0;
 }
 
index 23314be49480684c583aefffedec4587af48e524..164898b0010c68b350c175b705ef3534af5be69a 100644 (file)
@@ -460,10 +460,6 @@ static ssize_t radeon_get_dpm_state(struct device *dev,
        struct radeon_device *rdev = ddev->dev_private;
        enum radeon_pm_state_type pm = rdev->pm.dpm.user_state;
 
-       if  ((rdev->flags & RADEON_IS_PX) &&
-            (ddev->switch_power_state != DRM_SWITCH_POWER_ON))
-               return snprintf(buf, PAGE_SIZE, "off\n");
-
        return snprintf(buf, PAGE_SIZE, "%s\n",
                        (pm == POWER_STATE_TYPE_BATTERY) ? "battery" :
                        (pm == POWER_STATE_TYPE_BALANCED) ? "balanced" : "performance");
@@ -477,11 +473,6 @@ static ssize_t radeon_set_dpm_state(struct device *dev,
        struct drm_device *ddev = dev_get_drvdata(dev);
        struct radeon_device *rdev = ddev->dev_private;
 
-       /* Can't set dpm state when the card is off */
-       if  ((rdev->flags & RADEON_IS_PX) &&
-            (ddev->switch_power_state != DRM_SWITCH_POWER_ON))
-               return -EINVAL;
-
        mutex_lock(&rdev->pm.mutex);
        if (strncmp("battery", buf, strlen("battery")) == 0)
                rdev->pm.dpm.user_state = POWER_STATE_TYPE_BATTERY;
@@ -495,7 +486,12 @@ static ssize_t radeon_set_dpm_state(struct device *dev,
                goto fail;
        }
        mutex_unlock(&rdev->pm.mutex);
-       radeon_pm_compute_clocks(rdev);
+
+       /* Can't set dpm state when the card is off */
+       if (!(rdev->flags & RADEON_IS_PX) ||
+           (ddev->switch_power_state == DRM_SWITCH_POWER_ON))
+               radeon_pm_compute_clocks(rdev);
+
 fail:
        return count;
 }
index 5b4e0cf231a04d0a104868ed590f1324afe70be1..d65607902537f41a7ede21261eb111ddbf257e63 100644 (file)
@@ -177,16 +177,18 @@ int radeon_ring_lock(struct radeon_device *rdev, struct radeon_ring *ring, unsig
  *
  * @rdev: radeon_device pointer
  * @ring: radeon_ring structure holding ring information
+ * @hdp_flush: Whether or not to perform an HDP cache flush
  *
  * Update the wptr (write pointer) to tell the GPU to
  * execute new commands on the ring buffer (all asics).
  */
-void radeon_ring_commit(struct radeon_device *rdev, struct radeon_ring *ring)
+void radeon_ring_commit(struct radeon_device *rdev, struct radeon_ring *ring,
+                       bool hdp_flush)
 {
        /* If we are emitting the HDP flush via the ring buffer, we need to
         * do it before padding.
         */
-       if (rdev->asic->ring[ring->idx]->hdp_flush)
+       if (hdp_flush && rdev->asic->ring[ring->idx]->hdp_flush)
                rdev->asic->ring[ring->idx]->hdp_flush(rdev, ring);
        /* We pad to match fetch size */
        while (ring->wptr & ring->align_mask) {
@@ -196,7 +198,7 @@ void radeon_ring_commit(struct radeon_device *rdev, struct radeon_ring *ring)
        /* If we are emitting the HDP flush via MMIO, we need to do it after
         * all CPU writes to VRAM finished.
         */
-       if (rdev->asic->mmio_hdp_flush)
+       if (hdp_flush && rdev->asic->mmio_hdp_flush)
                rdev->asic->mmio_hdp_flush(rdev);
        radeon_ring_set_wptr(rdev, ring);
 }
@@ -207,12 +209,14 @@ void radeon_ring_commit(struct radeon_device *rdev, struct radeon_ring *ring)
  *
  * @rdev: radeon_device pointer
  * @ring: radeon_ring structure holding ring information
+ * @hdp_flush: Whether or not to perform an HDP cache flush
  *
  * Call radeon_ring_commit() then unlock the ring (all asics).
  */
-void radeon_ring_unlock_commit(struct radeon_device *rdev, struct radeon_ring *ring)
+void radeon_ring_unlock_commit(struct radeon_device *rdev, struct radeon_ring *ring,
+                              bool hdp_flush)
 {
-       radeon_ring_commit(rdev, ring);
+       radeon_ring_commit(rdev, ring, hdp_flush);
        mutex_unlock(&rdev->ring_lock);
 }
 
@@ -372,7 +376,7 @@ int radeon_ring_restore(struct radeon_device *rdev, struct radeon_ring *ring,
                radeon_ring_write(ring, data[i]);
        }
 
-       radeon_ring_unlock_commit(rdev, ring);
+       radeon_ring_unlock_commit(rdev, ring, false);
        kfree(data);
        return 0;
 }
@@ -400,9 +404,7 @@ int radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *ring, unsig
        /* Allocate ring buffer */
        if (ring->ring_obj == NULL) {
                r = radeon_bo_create(rdev, ring->ring_size, PAGE_SIZE, true,
-                                    RADEON_GEM_DOMAIN_GTT,
-                                    (rdev->flags & RADEON_IS_PCIE) ?
-                                    RADEON_GEM_GTT_WC : 0,
+                                    RADEON_GEM_DOMAIN_GTT, 0,
                                     NULL, &ring->ring_obj);
                if (r) {
                        dev_err(rdev->dev, "(%d) ring create failed\n", r);
index dbd6bcde92de412a87379d7da23a4cea74b40649..56d9fd66d8aed379c417d1ba4a47de7aa65ba472 100644 (file)
@@ -179,7 +179,7 @@ int radeon_semaphore_sync_rings(struct radeon_device *rdev,
                        continue;
                }
 
-               radeon_ring_commit(rdev, &rdev->ring[i]);
+               radeon_ring_commit(rdev, &rdev->ring[i], false);
                radeon_fence_note_sync(fence, ring);
 
                semaphore->gpu_addr += 8;
index 5adf4207453d7eb041f6679722283a36ae5a0931..17bc3dced9f1db921a11f80b1167f520261ed0b1 100644 (file)
@@ -288,7 +288,7 @@ static int radeon_test_create_and_emit_fence(struct radeon_device *rdev,
                        return r;
                }
                radeon_fence_emit(rdev, fence, ring->idx);
-               radeon_ring_unlock_commit(rdev, ring);
+               radeon_ring_unlock_commit(rdev, ring, false);
        }
        return 0;
 }
@@ -313,7 +313,7 @@ void radeon_test_ring_sync(struct radeon_device *rdev,
                goto out_cleanup;
        }
        radeon_semaphore_emit_wait(rdev, ringA->idx, semaphore);
-       radeon_ring_unlock_commit(rdev, ringA);
+       radeon_ring_unlock_commit(rdev, ringA, false);
 
        r = radeon_test_create_and_emit_fence(rdev, ringA, &fence1);
        if (r)
@@ -325,7 +325,7 @@ void radeon_test_ring_sync(struct radeon_device *rdev,
                goto out_cleanup;
        }
        radeon_semaphore_emit_wait(rdev, ringA->idx, semaphore);
-       radeon_ring_unlock_commit(rdev, ringA);
+       radeon_ring_unlock_commit(rdev, ringA, false);
 
        r = radeon_test_create_and_emit_fence(rdev, ringA, &fence2);
        if (r)
@@ -344,7 +344,7 @@ void radeon_test_ring_sync(struct radeon_device *rdev,
                goto out_cleanup;
        }
        radeon_semaphore_emit_signal(rdev, ringB->idx, semaphore);
-       radeon_ring_unlock_commit(rdev, ringB);
+       radeon_ring_unlock_commit(rdev, ringB, false);
 
        r = radeon_fence_wait(fence1, false);
        if (r) {
@@ -365,7 +365,7 @@ void radeon_test_ring_sync(struct radeon_device *rdev,
                goto out_cleanup;
        }
        radeon_semaphore_emit_signal(rdev, ringB->idx, semaphore);
-       radeon_ring_unlock_commit(rdev, ringB);
+       radeon_ring_unlock_commit(rdev, ringB, false);
 
        r = radeon_fence_wait(fence2, false);
        if (r) {
@@ -408,7 +408,7 @@ static void radeon_test_ring_sync2(struct radeon_device *rdev,
                goto out_cleanup;
        }
        radeon_semaphore_emit_wait(rdev, ringA->idx, semaphore);
-       radeon_ring_unlock_commit(rdev, ringA);
+       radeon_ring_unlock_commit(rdev, ringA, false);
 
        r = radeon_test_create_and_emit_fence(rdev, ringA, &fenceA);
        if (r)
@@ -420,7 +420,7 @@ static void radeon_test_ring_sync2(struct radeon_device *rdev,
                goto out_cleanup;
        }
        radeon_semaphore_emit_wait(rdev, ringB->idx, semaphore);
-       radeon_ring_unlock_commit(rdev, ringB);
+       radeon_ring_unlock_commit(rdev, ringB, false);
        r = radeon_test_create_and_emit_fence(rdev, ringB, &fenceB);
        if (r)
                goto out_cleanup;
@@ -442,7 +442,7 @@ static void radeon_test_ring_sync2(struct radeon_device *rdev,
                goto out_cleanup;
        }
        radeon_semaphore_emit_signal(rdev, ringC->idx, semaphore);
-       radeon_ring_unlock_commit(rdev, ringC);
+       radeon_ring_unlock_commit(rdev, ringC, false);
 
        for (i = 0; i < 30; ++i) {
                mdelay(100);
@@ -468,7 +468,7 @@ static void radeon_test_ring_sync2(struct radeon_device *rdev,
                goto out_cleanup;
        }
        radeon_semaphore_emit_signal(rdev, ringC->idx, semaphore);
-       radeon_ring_unlock_commit(rdev, ringC);
+       radeon_ring_unlock_commit(rdev, ringC, false);
 
        mdelay(1000);
 
index 6bf55ec85b62f7b3ee817356c6167181938a3dc1..341848a143761dd8236edc7862f79482d5d2d19d 100644 (file)
@@ -646,7 +646,7 @@ static int radeon_uvd_send_msg(struct radeon_device *rdev,
                ib.ptr[i] = PACKET2(0);
        ib.length_dw = 16;
 
-       r = radeon_ib_schedule(rdev, &ib, NULL);
+       r = radeon_ib_schedule(rdev, &ib, NULL, false);
        if (r)
                goto err;
        ttm_eu_fence_buffer_objects(&ticket, &head, ib.fence);
index f9b70a43aa524f4ccbcff640e28e0d21573463b6..c7190aadbd8981bee97c0c4ed4d923cdf7880b52 100644 (file)
@@ -368,7 +368,7 @@ int radeon_vce_get_create_msg(struct radeon_device *rdev, int ring,
        for (i = ib.length_dw; i < ib_size_dw; ++i)
                ib.ptr[i] = 0x0;
 
-       r = radeon_ib_schedule(rdev, &ib, NULL);
+       r = radeon_ib_schedule(rdev, &ib, NULL, false);
        if (r) {
                DRM_ERROR("radeon: failed to schedule ib (%d).\n", r);
        }
@@ -425,7 +425,7 @@ int radeon_vce_get_destroy_msg(struct radeon_device *rdev, int ring,
        for (i = ib.length_dw; i < ib_size_dw; ++i)
                ib.ptr[i] = 0x0;
 
-       r = radeon_ib_schedule(rdev, &ib, NULL);
+       r = radeon_ib_schedule(rdev, &ib, NULL, false);
        if (r) {
                DRM_ERROR("radeon: failed to schedule ib (%d).\n", r);
        }
@@ -715,7 +715,7 @@ int radeon_vce_ring_test(struct radeon_device *rdev, struct radeon_ring *ring)
                return r;
        }
        radeon_ring_write(ring, VCE_CMD_END);
-       radeon_ring_unlock_commit(rdev, ring);
+       radeon_ring_unlock_commit(rdev, ring, false);
 
        for (i = 0; i < rdev->usec_timeout; i++) {
                if (vce_v1_0_get_rptr(rdev, ring) != rptr)
index ccae4d9dc3deb6aefc3f131dbd9648c5ea374f1a..088ffdc2f577c06519e2a31bc90bbd402c940125 100644 (file)
@@ -420,7 +420,7 @@ static int radeon_vm_clear_bo(struct radeon_device *rdev,
        radeon_asic_vm_pad_ib(rdev, &ib);
        WARN_ON(ib.length_dw > 64);
 
-       r = radeon_ib_schedule(rdev, &ib, NULL);
+       r = radeon_ib_schedule(rdev, &ib, NULL, false);
        if (r)
                 goto error;
 
@@ -483,6 +483,10 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev,
                        /* add a clone of the bo_va to clear the old address */
                        struct radeon_bo_va *tmp;
                        tmp = kzalloc(sizeof(struct radeon_bo_va), GFP_KERNEL);
+                       if (!tmp) {
+                               mutex_unlock(&vm->mutex);
+                               return -ENOMEM;
+                       }
                        tmp->it.start = bo_va->it.start;
                        tmp->it.last = bo_va->it.last;
                        tmp->vm = vm;
@@ -693,7 +697,7 @@ int radeon_vm_update_page_directory(struct radeon_device *rdev,
                radeon_semaphore_sync_to(ib.semaphore, pd->tbo.sync_obj);
                radeon_semaphore_sync_to(ib.semaphore, vm->last_id_use);
                WARN_ON(ib.length_dw > ndw);
-               r = radeon_ib_schedule(rdev, &ib, NULL);
+               r = radeon_ib_schedule(rdev, &ib, NULL, false);
                if (r) {
                        radeon_ib_free(rdev, &ib);
                        return r;
@@ -957,7 +961,7 @@ int radeon_vm_bo_update(struct radeon_device *rdev,
        WARN_ON(ib.length_dw > ndw);
 
        radeon_semaphore_sync_to(ib.semaphore, vm->fence);
-       r = radeon_ib_schedule(rdev, &ib, NULL);
+       r = radeon_ib_schedule(rdev, &ib, NULL, false);
        if (r) {
                radeon_ib_free(rdev, &ib);
                return r;
index 3e21e869015fece1124e7093bfd028e99be2e909..8a477bf1fdb31529173234f8f30a0b4e3fb9c608 100644 (file)
@@ -124,7 +124,7 @@ void rv515_ring_start(struct radeon_device *rdev, struct radeon_ring *ring)
        radeon_ring_write(ring, GEOMETRY_ROUND_NEAREST | COLOR_ROUND_NEAREST);
        radeon_ring_write(ring, PACKET0(0x20C8, 0));
        radeon_ring_write(ring, 0);
-       radeon_ring_unlock_commit(rdev, ring);
+       radeon_ring_unlock_commit(rdev, ring, false);
 }
 
 int rv515_mc_wait_for_idle(struct radeon_device *rdev)
index 2983f17ea1b38399ab649dbb965cae291e6d9b82..d9f5ce715c9bfe5ff18be2a428809c1b7b217c58 100644 (file)
@@ -1177,7 +1177,6 @@ static void rv770_gpu_init(struct radeon_device *rdev)
        u32 hdp_host_path_cntl;
        u32 sq_dyn_gpr_size_simd_ab_0;
        u32 gb_tiling_config = 0;
-       u32 cc_rb_backend_disable = 0;
        u32 cc_gc_shader_pipe_config = 0;
        u32 mc_arb_ramcfg;
        u32 db_debug4, tmp;
@@ -1311,21 +1310,7 @@ static void rv770_gpu_init(struct radeon_device *rdev)
                WREG32(SPI_CONFIG_CNTL, 0);
        }
 
-       cc_rb_backend_disable = RREG32(CC_RB_BACKEND_DISABLE) & 0x00ff0000;
-       tmp = R7XX_MAX_BACKENDS - r600_count_pipe_bits(cc_rb_backend_disable >> 16);
-       if (tmp < rdev->config.rv770.max_backends) {
-               rdev->config.rv770.max_backends = tmp;
-       }
-
        cc_gc_shader_pipe_config = RREG32(CC_GC_SHADER_PIPE_CONFIG) & 0xffffff00;
-       tmp = R7XX_MAX_PIPES - r600_count_pipe_bits((cc_gc_shader_pipe_config >> 8) & R7XX_MAX_PIPES_MASK);
-       if (tmp < rdev->config.rv770.max_pipes) {
-               rdev->config.rv770.max_pipes = tmp;
-       }
-       tmp = R7XX_MAX_SIMDS - r600_count_pipe_bits((cc_gc_shader_pipe_config >> 16) & R7XX_MAX_SIMDS_MASK);
-       if (tmp < rdev->config.rv770.max_simds) {
-               rdev->config.rv770.max_simds = tmp;
-       }
        tmp = rdev->config.rv770.max_simds -
                r600_count_pipe_bits((cc_gc_shader_pipe_config >> 16) & R7XX_MAX_SIMDS_MASK);
        rdev->config.rv770.active_simds = tmp;
@@ -1348,6 +1333,14 @@ static void rv770_gpu_init(struct radeon_device *rdev)
        rdev->config.rv770.tiling_npipes = rdev->config.rv770.max_tile_pipes;
 
        disabled_rb_mask = (RREG32(CC_RB_BACKEND_DISABLE) >> 16) & R7XX_MAX_BACKENDS_MASK;
+       tmp = 0;
+       for (i = 0; i < rdev->config.rv770.max_backends; i++)
+               tmp |= (1 << i);
+       /* if all the backends are disabled, fix it up here */
+       if ((disabled_rb_mask & tmp) == tmp) {
+               for (i = 0; i < rdev->config.rv770.max_backends; i++)
+                       disabled_rb_mask &= ~(1 << i);
+       }
        tmp = (gb_tiling_config & PIPE_TILING__MASK) >> PIPE_TILING__SHIFT;
        tmp = r6xx_remap_render_backend(rdev, tmp, rdev->config.rv770.max_backends,
                                        R7XX_MAX_BACKENDS, disabled_rb_mask);
index bbf2e076ee457816924a736c57d2192cabba88ac..74426ac2bb5c2f39a26fb07eb76538afcc7061a9 100644 (file)
@@ -90,7 +90,7 @@ int rv770_copy_dma(struct radeon_device *rdev,
                return r;
        }
 
-       radeon_ring_unlock_commit(rdev, ring);
+       radeon_ring_unlock_commit(rdev, ring, false);
        radeon_semaphore_free(rdev, &sem, *fence);
 
        return r;
index 011779bd2b3da677129b38709742f673bbaa3398..6bce40847753b822f50be6037654c863833af068 100644 (file)
@@ -3057,7 +3057,7 @@ static void si_gpu_init(struct radeon_device *rdev)
        u32 sx_debug_1;
        u32 hdp_host_path_cntl;
        u32 tmp;
-       int i, j, k;
+       int i, j;
 
        switch (rdev->family) {
        case CHIP_TAHITI:
@@ -3255,12 +3255,11 @@ static void si_gpu_init(struct radeon_device *rdev)
                     rdev->config.si.max_sh_per_se,
                     rdev->config.si.max_cu_per_sh);
 
+       rdev->config.si.active_cus = 0;
        for (i = 0; i < rdev->config.si.max_shader_engines; i++) {
                for (j = 0; j < rdev->config.si.max_sh_per_se; j++) {
-                       for (k = 0; k < rdev->config.si.max_cu_per_sh; k++) {
-                               rdev->config.si.active_cus +=
-                                       hweight32(si_get_cu_active_bitmap(rdev, i, j));
-                       }
+                       rdev->config.si.active_cus +=
+                               hweight32(si_get_cu_active_bitmap(rdev, i, j));
                }
        }
 
@@ -3541,7 +3540,7 @@ static int si_cp_start(struct radeon_device *rdev)
        radeon_ring_write(ring, PACKET3_BASE_INDEX(CE_PARTITION_BASE));
        radeon_ring_write(ring, 0xc000);
        radeon_ring_write(ring, 0xe000);
-       radeon_ring_unlock_commit(rdev, ring);
+       radeon_ring_unlock_commit(rdev, ring, false);
 
        si_cp_enable(rdev, true);
 
@@ -3570,7 +3569,7 @@ static int si_cp_start(struct radeon_device *rdev)
        radeon_ring_write(ring, 0x0000000e); /* VGT_VERTEX_REUSE_BLOCK_CNTL */
        radeon_ring_write(ring, 0x00000010); /* VGT_OUT_DEALLOC_CNTL */
 
-       radeon_ring_unlock_commit(rdev, ring);
+       radeon_ring_unlock_commit(rdev, ring, false);
 
        for (i = RADEON_RING_TYPE_GFX_INDEX; i <= CAYMAN_RING_TYPE_CP2_INDEX; ++i) {
                ring = &rdev->ring[i];
@@ -3580,7 +3579,7 @@ static int si_cp_start(struct radeon_device *rdev)
                radeon_ring_write(ring, PACKET3_COMPUTE(PACKET3_CLEAR_STATE, 0));
                radeon_ring_write(ring, 0);
 
-               radeon_ring_unlock_commit(rdev, ring);
+               radeon_ring_unlock_commit(rdev, ring, false);
        }
 
        return 0;
@@ -4291,10 +4290,10 @@ static int si_pcie_gart_enable(struct radeon_device *rdev)
        for (i = 1; i < 16; i++) {
                if (i < 8)
                        WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (i << 2),
-                              rdev->gart.table_addr >> 12);
+                              rdev->vm_manager.saved_table_addr[i]);
                else
                        WREG32(VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((i - 8) << 2),
-                              rdev->gart.table_addr >> 12);
+                              rdev->vm_manager.saved_table_addr[i]);
        }
 
        /* enable context1-15 */
@@ -4326,6 +4325,17 @@ static int si_pcie_gart_enable(struct radeon_device *rdev)
 
 static void si_pcie_gart_disable(struct radeon_device *rdev)
 {
+       unsigned i;
+
+       for (i = 1; i < 16; ++i) {
+               uint32_t reg;
+               if (i < 8)
+                       reg = VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (i << 2);
+               else
+                       reg = VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((i - 8) << 2);
+               rdev->vm_manager.saved_table_addr[i] = RREG32(reg);
+       }
+
        /* Disable all tables */
        WREG32(VM_CONTEXT0_CNTL, 0);
        WREG32(VM_CONTEXT1_CNTL, 0);
@@ -5028,7 +5038,7 @@ void si_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
 
        /* flush hdp cache */
        radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
-       radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
+       radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(1) |
                                 WRITE_DATA_DST_SEL(0)));
        radeon_ring_write(ring, HDP_MEM_COHERENCY_FLUSH_CNTL >> 2);
        radeon_ring_write(ring, 0);
@@ -5036,7 +5046,7 @@ void si_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
 
        /* bits 0-15 are the VM contexts0-15 */
        radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
-       radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
+       radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(1) |
                                 WRITE_DATA_DST_SEL(0)));
        radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2);
        radeon_ring_write(ring, 0);
@@ -7178,6 +7188,9 @@ static void si_pcie_gen3_enable(struct radeon_device *rdev)
        int ret, i;
        u16 tmp16;
 
+       if (pci_is_root_bus(rdev->pdev->bus))
+               return;
+
        if (radeon_pcie_gen2 == 0)
                return;
 
@@ -7455,7 +7468,8 @@ static void si_program_aspm(struct radeon_device *rdev)
                        if (orig != data)
                                WREG32_PIF_PHY1(PB1_PIF_CNTL, data);
 
-                       if (!disable_clkreq) {
+                       if (!disable_clkreq &&
+                           !pci_is_root_bus(rdev->pdev->bus)) {
                                struct pci_dev *root = rdev->pdev->bus->self;
                                u32 lnkcap;
 
index 7165051294504470c24e054b384802f05dc24de7..7c22baaf94dbf9ac598f745bfb35b2f5ba5138f2 100644 (file)
@@ -275,7 +275,7 @@ int si_copy_dma(struct radeon_device *rdev,
                return r;
        }
 
-       radeon_ring_unlock_commit(rdev, ring);
+       radeon_ring_unlock_commit(rdev, ring, false);
        radeon_semaphore_free(rdev, &sem, *fence);
 
        return r;
index 32e50be9c4ac1c41969fd9de2d1a6a3439a6ef27..57f780053b3e4d2717a69b9e60e5aa5967fffc3d 100644 (file)
@@ -1874,16 +1874,22 @@ int trinity_dpm_init(struct radeon_device *rdev)
        for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++)
                pi->at[i] = TRINITY_AT_DFLT;
 
-       /* There are stability issues reported on with
-        * bapm enabled when switching between AC and battery
-        * power.  At the same time, some MSI boards hang
-        * if it's not enabled and dpm is enabled.  Just enable
-        * it for MSI boards right now.
-        */
-       if (rdev->pdev->subsystem_vendor == 0x1462)
-               pi->enable_bapm = true;
-       else
+       if (radeon_bapm == -1) {
+               /* There are stability issues reported on with
+                * bapm enabled when switching between AC and battery
+                * power.  At the same time, some MSI boards hang
+                * if it's not enabled and dpm is enabled.  Just enable
+                * it for MSI boards right now.
+                */
+               if (rdev->pdev->subsystem_vendor == 0x1462)
+                       pi->enable_bapm = true;
+               else
+                       pi->enable_bapm = false;
+       } else if (radeon_bapm == 0) {
                pi->enable_bapm = false;
+       } else {
+               pi->enable_bapm = true;
+       }
        pi->enable_nbps_policy = true;
        pi->enable_sclk_ds = true;
        pi->enable_gfx_power_gating = true;
index be42c8125203b22bd62d9fc4be8510672ba577b3..cda391347286c3545bdd952234b3b5fb7186a5d9 100644 (file)
@@ -124,7 +124,7 @@ int uvd_v1_0_init(struct radeon_device *rdev)
        radeon_ring_write(ring, PACKET0(UVD_SEMA_CNTL, 0));
        radeon_ring_write(ring, 3);
 
-       radeon_ring_unlock_commit(rdev, ring);
+       radeon_ring_unlock_commit(rdev, ring, false);
 
 done:
        /* lower clocks again */
@@ -331,7 +331,7 @@ int uvd_v1_0_ring_test(struct radeon_device *rdev, struct radeon_ring *ring)
        }
        radeon_ring_write(ring, PACKET0(UVD_CONTEXT_ID, 0));
        radeon_ring_write(ring, 0xDEADBEEF);
-       radeon_ring_unlock_commit(rdev, ring);
+       radeon_ring_unlock_commit(rdev, ring, false);
        for (i = 0; i < rdev->usec_timeout; i++) {
                tmp = RREG32(UVD_CONTEXT_ID);
                if (tmp == 0xDEADBEEF)
index 2d9d4252d59867a3aef9ffba5552d7fb3d79e242..ae8850f3e63bc4669e796650a1b76a9e9ff21a9f 100644 (file)
@@ -1,6 +1,7 @@
 config DRM_STI
        tristate "DRM Support for STMicroelectronics SoC stiH41x Series"
        depends on DRM && (SOC_STIH415 || SOC_STIH416 || ARCH_MULTIPLATFORM)
+       select RESET_CONTROLLER
        select DRM_KMS_HELPER
        select DRM_GEM_CMA_HELPER
        select DRM_KMS_CMA_HELPER
index a7cc24917a96c39d9179e55744703171142c3bf5..223d93c3a05d8d7241ad05b669562d0a160af4fa 100644 (file)
@@ -201,8 +201,8 @@ static int sti_drm_platform_probe(struct platform_device *pdev)
        master = platform_device_register_resndata(dev,
                        DRIVER_NAME "__master", -1,
                        NULL, 0, NULL, 0);
-       if (!master)
-               return -EINVAL;
+       if (IS_ERR(master))
+               return PTR_ERR(master);
 
        platform_set_drvdata(pdev, master);
        return 0;
index 72d957f81c057790ad504d2cc626ee6cf08fd721..2ae9a9b7366660632f1745a1dce3e60cf7f03532 100644 (file)
@@ -730,16 +730,16 @@ static int sti_hda_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
        hda->regs = devm_ioremap_nocache(dev, res->start, resource_size(res));
-       if (IS_ERR(hda->regs))
-               return PTR_ERR(hda->regs);
+       if (!hda->regs)
+               return -ENOMEM;
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
                        "video-dacs-ctrl");
        if (res) {
                hda->video_dacs_ctrl = devm_ioremap_nocache(dev, res->start,
                                resource_size(res));
-               if (IS_ERR(hda->video_dacs_ctrl))
-                       return PTR_ERR(hda->video_dacs_ctrl);
+               if (!hda->video_dacs_ctrl)
+                       return -ENOMEM;
        } else {
                /* If no existing video-dacs-ctrl resource continue the probe */
                DRM_DEBUG_DRIVER("No video-dacs-ctrl resource\n");
@@ -770,7 +770,7 @@ static int sti_hda_remove(struct platform_device *pdev)
        return 0;
 }
 
-static struct of_device_id hda_of_match[] = {
+static const struct of_device_id hda_of_match[] = {
        { .compatible = "st,stih416-hda", },
        { .compatible = "st,stih407-hda", },
        { /* end node */ }
index 284e541d970d8a1ec2213d2479f3d0f7c29176f7..ef93156a69c6fdad9dd2af368ef68e8ecd9a9b9a 100644 (file)
@@ -677,7 +677,7 @@ static const struct component_ops sti_hdmi_ops = {
        .unbind = sti_hdmi_unbind,
 };
 
-static struct of_device_id hdmi_of_match[] = {
+static const struct of_device_id hdmi_of_match[] = {
        {
                .compatible = "st,stih416-hdmi",
                .data = &tx3g0c55phy_ops,
@@ -713,8 +713,8 @@ static int sti_hdmi_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
        hdmi->regs = devm_ioremap_nocache(dev, res->start, resource_size(res));
-       if (IS_ERR(hdmi->regs))
-               return PTR_ERR(hdmi->regs);
+       if (!hdmi->regs)
+               return -ENOMEM;
 
        if (of_device_is_compatible(np, "st,stih416-hdmi")) {
                res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
@@ -725,8 +725,8 @@ static int sti_hdmi_probe(struct platform_device *pdev)
                }
                hdmi->syscfg = devm_ioremap_nocache(dev, res->start,
                                                    resource_size(res));
-               if (IS_ERR(hdmi->syscfg))
-                       return PTR_ERR(hdmi->syscfg);
+               if (!hdmi->syscfg)
+                       return -ENOMEM;
 
        }
 
index b69e26fee76e0736af3062053e25b41cd47979f9..b8afe490356aedf09bb361d295764020dfff5eac 100644 (file)
@@ -591,8 +591,8 @@ static int sti_tvout_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
        tvout->regs = devm_ioremap_nocache(dev, res->start, resource_size(res));
-       if (IS_ERR(tvout->regs))
-               return PTR_ERR(tvout->regs);
+       if (!tvout->regs)
+               return -ENOMEM;
 
        /* get reset resources */
        tvout->reset = devm_reset_control_get(dev, "tvout");
@@ -624,7 +624,7 @@ static int sti_tvout_remove(struct platform_device *pdev)
        return 0;
 }
 
-static struct of_device_id tvout_of_match[] = {
+static const struct of_device_id tvout_of_match[] = {
        { .compatible = "st,stih416-tvout", },
        { .compatible = "st,stih407-tvout", },
        { /* end node */ }
index 7bfdaa163a33a19fb7ca8d775e654277aea497ea..36b871686d3c6147a7b033b9db45a07ed39e9530 100644 (file)
@@ -450,11 +450,11 @@ static int vmw_cmd_res_reloc_add(struct vmw_private *dev_priv,
                                          res,
                                          id_loc - sw_context->buf_start);
        if (unlikely(ret != 0))
-               goto out_err;
+               return ret;
 
        ret = vmw_resource_val_add(sw_context, res, &node);
        if (unlikely(ret != 0))
-               goto out_err;
+               return ret;
 
        if (res_type == vmw_res_context && dev_priv->has_mob &&
            node->first_usage) {
@@ -468,13 +468,13 @@ static int vmw_cmd_res_reloc_add(struct vmw_private *dev_priv,
 
                ret = vmw_resource_context_res_add(dev_priv, sw_context, res);
                if (unlikely(ret != 0))
-                       goto out_err;
+                       return ret;
                node->staged_bindings =
                        kzalloc(sizeof(*node->staged_bindings), GFP_KERNEL);
                if (node->staged_bindings == NULL) {
                        DRM_ERROR("Failed to allocate context binding "
                                  "information.\n");
-                       goto out_err;
+                       return -ENOMEM;
                }
                INIT_LIST_HEAD(&node->staged_bindings->list);
        }
@@ -482,8 +482,7 @@ static int vmw_cmd_res_reloc_add(struct vmw_private *dev_priv,
        if (p_val)
                *p_val = node;
 
-out_err:
-       return ret;
+       return 0;
 }
 
 
index 6ccd993e26bf4ead66d0e8d1f1b4b592856d7599..6eae14d2a3f73511143a42da95757418edf01207 100644 (file)
@@ -180,8 +180,9 @@ void vmw_fifo_release(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo)
 
        mutex_lock(&dev_priv->hw_mutex);
 
+       vmw_write(dev_priv, SVGA_REG_SYNC, SVGA_SYNC_GENERIC);
        while (vmw_read(dev_priv, SVGA_REG_BUSY) != 0)
-               vmw_write(dev_priv, SVGA_REG_SYNC, SVGA_SYNC_GENERIC);
+               ;
 
        dev_priv->last_read_seqno = ioread32(fifo_mem + SVGA_FIFO_FENCE);
 
index 1bdcccc54a1dda0e04d16fc9fbfe2d3d8e1e22b2..f745d2c1325ec8872a376e668cdd71b3c9c523f3 100644 (file)
@@ -28,7 +28,7 @@
 static __u8 *ch_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                unsigned int *rsize)
 {
-       if (*rsize >= 17 && rdesc[11] == 0x3c && rdesc[12] == 0x02) {
+       if (*rsize >= 18 && rdesc[11] == 0x3c && rdesc[12] == 0x02) {
                hid_info(hdev, "fixing up Cherry Cymotion report descriptor\n");
                rdesc[11] = rdesc[16] = 0xff;
                rdesc[12] = rdesc[17] = 0x03;
index 60f44cd1b0ed30ec19e986800676311bb72dadac..61b68ca27790d65c270465af7152276d7d7be7c9 100644 (file)
@@ -84,6 +84,15 @@ static const __u8 huion_tablet_rdesc_template[] = {
        0xC0                    /*  End Collection                          */
 };
 
+/* Parameter indices */
+enum huion_prm {
+       HUION_PRM_X_LM          = 1,
+       HUION_PRM_Y_LM          = 2,
+       HUION_PRM_PRESSURE_LM   = 4,
+       HUION_PRM_RESOLUTION    = 5,
+       HUION_PRM_NUM
+};
+
 /* Driver data */
 struct huion_drvdata {
        __u8 *rdesc;
@@ -115,7 +124,12 @@ static int huion_tablet_enable(struct hid_device *hdev)
        int rc;
        struct usb_device *usb_dev = hid_to_usb_dev(hdev);
        struct huion_drvdata *drvdata = hid_get_drvdata(hdev);
-       __le16 buf[6];
+       __le16 *buf = NULL;
+       size_t len;
+       s32 params[HUION_PH_ID_NUM];
+       s32 resolution;
+       __u8 *p;
+       s32 v;
 
        /*
         * Read string descriptor containing tablet parameters. The specific
@@ -123,65 +137,79 @@ static int huion_tablet_enable(struct hid_device *hdev)
         * driver traffic.
         * NOTE: This enables fully-functional tablet mode.
         */
+       len = HUION_PRM_NUM * sizeof(*buf);
+       buf = kmalloc(len, GFP_KERNEL);
+       if (buf == NULL) {
+               hid_err(hdev, "failed to allocate parameter buffer\n");
+               rc = -ENOMEM;
+               goto cleanup;
+       }
        rc = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
                                USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
                                (USB_DT_STRING << 8) + 0x64,
-                               0x0409, buf, sizeof(buf),
+                               0x0409, buf, len,
                                USB_CTRL_GET_TIMEOUT);
-       if (rc == -EPIPE)
-               hid_warn(hdev, "device parameters not found\n");
-       else if (rc < 0)
-               hid_warn(hdev, "failed to get device parameters: %d\n", rc);
-       else if (rc != sizeof(buf))
-               hid_warn(hdev, "invalid device parameters\n");
-       else {
-               s32 params[HUION_PH_ID_NUM];
-               s32 resolution;
-               __u8 *p;
-               s32 v;
+       if (rc == -EPIPE) {
+               hid_err(hdev, "device parameters not found\n");
+               rc = -ENODEV;
+               goto cleanup;
+       } else if (rc < 0) {
+               hid_err(hdev, "failed to get device parameters: %d\n", rc);
+               rc = -ENODEV;
+               goto cleanup;
+       } else if (rc != len) {
+               hid_err(hdev, "invalid device parameters\n");
+               rc = -ENODEV;
+               goto cleanup;
+       }
 
-               /* Extract device parameters */
-               params[HUION_PH_ID_X_LM] = le16_to_cpu(buf[1]);
-               params[HUION_PH_ID_Y_LM] = le16_to_cpu(buf[2]);
-               params[HUION_PH_ID_PRESSURE_LM] = le16_to_cpu(buf[4]);
-               resolution = le16_to_cpu(buf[5]);
-               if (resolution == 0) {
-                       params[HUION_PH_ID_X_PM] = 0;
-                       params[HUION_PH_ID_Y_PM] = 0;
-               } else {
-                       params[HUION_PH_ID_X_PM] = params[HUION_PH_ID_X_LM] *
-                                                       1000 / resolution;
-                       params[HUION_PH_ID_Y_PM] = params[HUION_PH_ID_Y_LM] *
-                                                       1000 / resolution;
-               }
+       /* Extract device parameters */
+       params[HUION_PH_ID_X_LM] = le16_to_cpu(buf[HUION_PRM_X_LM]);
+       params[HUION_PH_ID_Y_LM] = le16_to_cpu(buf[HUION_PRM_Y_LM]);
+       params[HUION_PH_ID_PRESSURE_LM] =
+               le16_to_cpu(buf[HUION_PRM_PRESSURE_LM]);
+       resolution = le16_to_cpu(buf[HUION_PRM_RESOLUTION]);
+       if (resolution == 0) {
+               params[HUION_PH_ID_X_PM] = 0;
+               params[HUION_PH_ID_Y_PM] = 0;
+       } else {
+               params[HUION_PH_ID_X_PM] = params[HUION_PH_ID_X_LM] *
+                                               1000 / resolution;
+               params[HUION_PH_ID_Y_PM] = params[HUION_PH_ID_Y_LM] *
+                                               1000 / resolution;
+       }
 
-               /* Allocate fixed report descriptor */
-               drvdata->rdesc = devm_kmalloc(&hdev->dev,
-                                       sizeof(huion_tablet_rdesc_template),
-                                       GFP_KERNEL);
-               if (drvdata->rdesc == NULL) {
-                       hid_err(hdev, "failed to allocate fixed rdesc\n");
-                       return -ENOMEM;
-               }
-               drvdata->rsize = sizeof(huion_tablet_rdesc_template);
+       /* Allocate fixed report descriptor */
+       drvdata->rdesc = devm_kmalloc(&hdev->dev,
+                               sizeof(huion_tablet_rdesc_template),
+                               GFP_KERNEL);
+       if (drvdata->rdesc == NULL) {
+               hid_err(hdev, "failed to allocate fixed rdesc\n");
+               rc = -ENOMEM;
+               goto cleanup;
+       }
+       drvdata->rsize = sizeof(huion_tablet_rdesc_template);
 
-               /* Format fixed report descriptor */
-               memcpy(drvdata->rdesc, huion_tablet_rdesc_template,
-                       drvdata->rsize);
-               for (p = drvdata->rdesc;
-                    p <= drvdata->rdesc + drvdata->rsize - 4;) {
-                       if (p[0] == 0xFE && p[1] == 0xED && p[2] == 0x1D &&
-                           p[3] < sizeof(params)) {
-                               v = params[p[3]];
-                               put_unaligned(cpu_to_le32(v), (s32 *)p);
-                               p += 4;
-                       } else {
-                               p++;
-                       }
+       /* Format fixed report descriptor */
+       memcpy(drvdata->rdesc, huion_tablet_rdesc_template,
+               drvdata->rsize);
+       for (p = drvdata->rdesc;
+            p <= drvdata->rdesc + drvdata->rsize - 4;) {
+               if (p[0] == 0xFE && p[1] == 0xED && p[2] == 0x1D &&
+                   p[3] < sizeof(params)) {
+                       v = params[p[3]];
+                       put_unaligned(cpu_to_le32(v), (s32 *)p);
+                       p += 4;
+               } else {
+                       p++;
                }
        }
 
-       return 0;
+       rc = 0;
+
+cleanup:
+       kfree(buf);
+       return rc;
 }
 
 static int huion_probe(struct hid_device *hdev, const struct hid_device_id *id)
index e7769636759129f2540c5c670f1cc332180191fe..b92bf01a1ae8122f486ea333288558f082162f5d 100644 (file)
@@ -300,7 +300,7 @@ static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                 *   - change the button usage range to 4-7 for the extra
                 *     buttons
                 */
-               if (*rsize >= 74 &&
+               if (*rsize >= 75 &&
                        rdesc[61] == 0x05 && rdesc[62] == 0x08 &&
                        rdesc[63] == 0x19 && rdesc[64] == 0x08 &&
                        rdesc[65] == 0x29 && rdesc[66] == 0x0f &&
index a976f48263f661248f818685d10b708496298cf0..f91ff145db9a0761ce487aa2b43aee1f2503af2f 100644 (file)
@@ -345,14 +345,14 @@ static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
        struct usb_device_descriptor *udesc;
        __u16 bcdDevice, rev_maj, rev_min;
 
-       if ((drv_data->quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 &&
+       if ((drv_data->quirks & LG_RDESC) && *rsize >= 91 && rdesc[83] == 0x26 &&
                        rdesc[84] == 0x8c && rdesc[85] == 0x02) {
                hid_info(hdev,
                         "fixing up Logitech keyboard report descriptor\n");
                rdesc[84] = rdesc[89] = 0x4d;
                rdesc[85] = rdesc[90] = 0x10;
        }
-       if ((drv_data->quirks & LG_RDESC_REL_ABS) && *rsize >= 50 &&
+       if ((drv_data->quirks & LG_RDESC_REL_ABS) && *rsize >= 51 &&
                        rdesc[32] == 0x81 && rdesc[33] == 0x06 &&
                        rdesc[49] == 0x81 && rdesc[50] == 0x06) {
                hid_info(hdev,
index cc2bd20221989aa0284269cce533c28ab2e7295c..7835717bc02011d4ed2638caca9472021394245b 100644 (file)
@@ -451,13 +451,13 @@ static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *at
        drv_data = hid_get_drvdata(hid);
        if (!drv_data) {
                hid_err(hid, "Private driver data not found!\n");
-               return 0;
+               return -EINVAL;
        }
 
        entry = drv_data->device_props;
        if (!entry) {
                hid_err(hid, "Device properties not found!\n");
-               return 0;
+               return -EINVAL;
        }
 
        if (range == 0)
index 486dbde2ba2d90d3802e59163870b57c4274fb28..9bf8637747a57f1b362680eeb36faf649b35f2fd 100644 (file)
@@ -238,13 +238,6 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
                return;
        }
 
-       if ((dj_report->device_index < DJ_DEVICE_INDEX_MIN) ||
-           (dj_report->device_index > DJ_DEVICE_INDEX_MAX)) {
-               dev_err(&djrcv_hdev->dev, "%s: invalid device index:%d\n",
-                       __func__, dj_report->device_index);
-               return;
-       }
-
        if (djrcv_dev->paired_dj_devices[dj_report->device_index]) {
                /* The device is already known. No need to reallocate it. */
                dbg_hid("%s: device is already known\n", __func__);
@@ -557,7 +550,7 @@ static int logi_dj_ll_raw_request(struct hid_device *hid,
        if (!out_buf)
                return -ENOMEM;
 
-       if (count < DJREPORT_SHORT_LENGTH - 2)
+       if (count > DJREPORT_SHORT_LENGTH - 2)
                count = DJREPORT_SHORT_LENGTH - 2;
 
        out_buf[0] = REPORT_ID_DJ_SHORT;
@@ -663,7 +656,6 @@ static int logi_dj_raw_event(struct hid_device *hdev,
        struct dj_receiver_dev *djrcv_dev = hid_get_drvdata(hdev);
        struct dj_report *dj_report = (struct dj_report *) data;
        unsigned long flags;
-       bool report_processed = false;
 
        dbg_hid("%s, size:%d\n", __func__, size);
 
@@ -691,27 +683,41 @@ static int logi_dj_raw_event(struct hid_device *hdev,
         * anything else with it.
         */
 
+       /* case 1) */
+       if (data[0] != REPORT_ID_DJ_SHORT)
+               return false;
+
+       if ((dj_report->device_index < DJ_DEVICE_INDEX_MIN) ||
+           (dj_report->device_index > DJ_DEVICE_INDEX_MAX)) {
+               /*
+                * Device index is wrong, bail out.
+                * This driver can ignore safely the receiver notifications,
+                * so ignore those reports too.
+                */
+               if (dj_report->device_index != DJ_RECEIVER_INDEX)
+                       dev_err(&hdev->dev, "%s: invalid device index:%d\n",
+                               __func__, dj_report->device_index);
+               return false;
+       }
+
        spin_lock_irqsave(&djrcv_dev->lock, flags);
-       if (dj_report->report_id == REPORT_ID_DJ_SHORT) {
-               switch (dj_report->report_type) {
-               case REPORT_TYPE_NOTIF_DEVICE_PAIRED:
-               case REPORT_TYPE_NOTIF_DEVICE_UNPAIRED:
-                       logi_dj_recv_queue_notification(djrcv_dev, dj_report);
-                       break;
-               case REPORT_TYPE_NOTIF_CONNECTION_STATUS:
-                       if (dj_report->report_params[CONNECTION_STATUS_PARAM_STATUS] ==
-                           STATUS_LINKLOSS) {
-                               logi_dj_recv_forward_null_report(djrcv_dev, dj_report);
-                       }
-                       break;
-               default:
-                       logi_dj_recv_forward_report(djrcv_dev, dj_report);
+       switch (dj_report->report_type) {
+       case REPORT_TYPE_NOTIF_DEVICE_PAIRED:
+       case REPORT_TYPE_NOTIF_DEVICE_UNPAIRED:
+               logi_dj_recv_queue_notification(djrcv_dev, dj_report);
+               break;
+       case REPORT_TYPE_NOTIF_CONNECTION_STATUS:
+               if (dj_report->report_params[CONNECTION_STATUS_PARAM_STATUS] ==
+                   STATUS_LINKLOSS) {
+                       logi_dj_recv_forward_null_report(djrcv_dev, dj_report);
                }
-               report_processed = true;
+               break;
+       default:
+               logi_dj_recv_forward_report(djrcv_dev, dj_report);
        }
        spin_unlock_irqrestore(&djrcv_dev->lock, flags);
 
-       return report_processed;
+       return true;
 }
 
 static int logi_dj_probe(struct hid_device *hdev,
index 4a4000340ce1ed8cf6be1f81ee8e0f21d8ba5f5a..daeb0aa4bee99a60f3391c0ab4a56803b37a2568 100644 (file)
@@ -27,6 +27,7 @@
 
 #define DJ_MAX_PAIRED_DEVICES                  6
 #define DJ_MAX_NUMBER_NOTIFICATIONS            8
+#define DJ_RECEIVER_INDEX                      0
 #define DJ_DEVICE_INDEX_MIN                    1
 #define DJ_DEVICE_INDEX_MAX                    6
 
index ecc2cbf300cc39bc31e3ff5ad5979dff49822402..29a74c1efcb85fa727536c4b72be844f9963cd70 100644 (file)
@@ -290,6 +290,11 @@ static int magicmouse_raw_event(struct hid_device *hdev,
                if (size < 4 || ((size - 4) % 9) != 0)
                        return 0;
                npoints = (size - 4) / 9;
+               if (npoints > 15) {
+                       hid_warn(hdev, "invalid size value (%d) for TRACKPAD_REPORT_ID\n",
+                                       size);
+                       return 0;
+               }
                msc->ntouches = 0;
                for (ii = 0; ii < npoints; ii++)
                        magicmouse_emit_touch(msc, ii, data + ii * 9 + 4);
@@ -307,6 +312,11 @@ static int magicmouse_raw_event(struct hid_device *hdev,
                if (size < 6 || ((size - 6) % 8) != 0)
                        return 0;
                npoints = (size - 6) / 8;
+               if (npoints > 15) {
+                       hid_warn(hdev, "invalid size value (%d) for MOUSE_REPORT_ID\n",
+                                       size);
+                       return 0;
+               }
                msc->ntouches = 0;
                for (ii = 0; ii < npoints; ii++)
                        magicmouse_emit_touch(msc, ii, data + ii * 8 + 6);
index 9e14c00eb1b6bb105ffd1326dc802183cfeb9a1a..25daf28b26bdf6b4d921e501bb49d4646e9aed55 100644 (file)
@@ -24,7 +24,7 @@
 static __u8 *mr_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                unsigned int *rsize)
 {
-       if (*rsize >= 30 && rdesc[29] == 0x05 && rdesc[30] == 0x09) {
+       if (*rsize >= 31 && rdesc[29] == 0x05 && rdesc[30] == 0x09) {
                hid_info(hdev, "fixing up button/consumer in HID report descriptor\n");
                rdesc[30] = 0x0c;
        }
index 736b2502df4f8b00473889f6abf0ac78dcf72fe3..6aca4f2554bf4d748df6fc629276704e740ea40e 100644 (file)
@@ -25,7 +25,7 @@
 static __u8 *pl_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                unsigned int *rsize)
 {
-       if (*rsize >= 60 && rdesc[39] == 0x2a && rdesc[40] == 0xf5 &&
+       if (*rsize >= 62 && rdesc[39] == 0x2a && rdesc[40] == 0xf5 &&
                        rdesc[41] == 0x00 && rdesc[59] == 0x26 &&
                        rdesc[60] == 0xf9 && rdesc[61] == 0x00) {
                hid_info(hdev, "fixing up Petalynx Maxter Remote report descriptor\n");
index acbb021065ece8287c9d3ea433c860afc0711855..020df3c2e8b42717c62bbe0470aa47845535e4a5 100644 (file)
@@ -350,6 +350,12 @@ static int picolcd_raw_event(struct hid_device *hdev,
        if (!data)
                return 1;
 
+       if (size > 64) {
+               hid_warn(hdev, "invalid size value (%d) for picolcd raw event\n",
+                               size);
+               return 0;
+       }
+
        if (report->id == REPORT_KEY_STATE) {
                if (data->input_keys)
                        ret = picolcd_raw_keypad(data, report, raw_data+1, size-1);
index 0dc25142f451ff8d5fb040249d83d811a029db1d..8389e8109218c7013567b727cdb3ae300c3a51b9 100644 (file)
@@ -909,10 +909,15 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id)
                return ret;
        }
 
-       if (!test_bit(RMI_STARTED, &data->flags)) {
-               hid_hw_stop(hdev);
-               return -EIO;
-       }
+       if (!test_bit(RMI_STARTED, &data->flags))
+               /*
+                * The device maybe in the bootloader if rmi_input_configured
+                * failed to find F11 in the PDT. Print an error, but don't
+                * return an error from rmi_probe so that hidraw will be
+                * accessible from userspace. That way a userspace tool
+                * can be used to reload working firmware on the touchpad.
+                */
+               hid_err(hdev, "Device failed to be properly configured\n");
 
        return 0;
 }
index e244e449cbbadc05ffc40c62e27fa1065c5154ed..2ac25760a9a9da02004299ab702c481d7e712cc5 100644 (file)
@@ -604,9 +604,9 @@ static int sensor_hub_probe(struct hid_device *hdev,
                ret = -EINVAL;
                goto err_stop_hw;
        }
-       sd->hid_sensor_hub_client_devs = kzalloc(dev_cnt *
-                                               sizeof(struct mfd_cell),
-                                               GFP_KERNEL);
+       sd->hid_sensor_hub_client_devs = devm_kzalloc(&hdev->dev, dev_cnt *
+                                                     sizeof(struct mfd_cell),
+                                                     GFP_KERNEL);
        if (sd->hid_sensor_hub_client_devs == NULL) {
                hid_err(hdev, "Failed to allocate memory for mfd cells\n");
                        ret = -ENOMEM;
@@ -618,11 +618,12 @@ static int sensor_hub_probe(struct hid_device *hdev,
 
                if (collection->type == HID_COLLECTION_PHYSICAL) {
 
-                       hsdev = kzalloc(sizeof(*hsdev), GFP_KERNEL);
+                       hsdev = devm_kzalloc(&hdev->dev, sizeof(*hsdev),
+                                            GFP_KERNEL);
                        if (!hsdev) {
                                hid_err(hdev, "cannot allocate hid_sensor_hub_device\n");
                                ret = -ENOMEM;
-                               goto err_no_mem;
+                               goto err_stop_hw;
                        }
                        hsdev->hdev = hdev;
                        hsdev->vendor_id = hdev->vendor;
@@ -631,13 +632,13 @@ static int sensor_hub_probe(struct hid_device *hdev,
                        if (last_hsdev)
                                last_hsdev->end_collection_index = i;
                        last_hsdev = hsdev;
-                       name = kasprintf(GFP_KERNEL, "HID-SENSOR-%x",
-                                       collection->usage);
+                       name = devm_kasprintf(&hdev->dev, GFP_KERNEL,
+                                             "HID-SENSOR-%x",
+                                             collection->usage);
                        if (name == NULL) {
                                hid_err(hdev, "Failed MFD device name\n");
                                        ret = -ENOMEM;
-                                       kfree(hsdev);
-                                       goto err_no_mem;
+                                       goto err_stop_hw;
                        }
                        sd->hid_sensor_hub_client_devs[
                                sd->hid_sensor_client_cnt].id =
@@ -661,16 +662,10 @@ static int sensor_hub_probe(struct hid_device *hdev,
        ret = mfd_add_devices(&hdev->dev, 0, sd->hid_sensor_hub_client_devs,
                sd->hid_sensor_client_cnt, NULL, 0, NULL);
        if (ret < 0)
-               goto err_no_mem;
+               goto err_stop_hw;
 
        return ret;
 
-err_no_mem:
-       for (i = 0; i < sd->hid_sensor_client_cnt; ++i) {
-               kfree(sd->hid_sensor_hub_client_devs[i].name);
-               kfree(sd->hid_sensor_hub_client_devs[i].platform_data);
-       }
-       kfree(sd->hid_sensor_hub_client_devs);
 err_stop_hw:
        hid_hw_stop(hdev);
 
@@ -681,7 +676,6 @@ static void sensor_hub_remove(struct hid_device *hdev)
 {
        struct sensor_hub_data *data = hid_get_drvdata(hdev);
        unsigned long flags;
-       int i;
 
        hid_dbg(hdev, " hardware removed\n");
        hid_hw_close(hdev);
@@ -691,11 +685,6 @@ static void sensor_hub_remove(struct hid_device *hdev)
                complete(&data->pending.ready);
        spin_unlock_irqrestore(&data->lock, flags);
        mfd_remove_devices(&hdev->dev);
-       for (i = 0; i < data->hid_sensor_client_cnt; ++i) {
-               kfree(data->hid_sensor_hub_client_devs[i].name);
-               kfree(data->hid_sensor_hub_client_devs[i].platform_data);
-       }
-       kfree(data->hid_sensor_hub_client_devs);
        hid_set_drvdata(hdev, NULL);
        mutex_destroy(&data->mutex);
 }
index 87fc91e1c8de4980d2f8e8721f476b6d21959adf..91072fa54663e747908dd09bb11b431eaa4208c5 100644 (file)
@@ -24,7 +24,7 @@
 static __u8 *sp_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                unsigned int *rsize)
 {
-       if (*rsize >= 107 && rdesc[104] == 0x26 && rdesc[105] == 0x80 &&
+       if (*rsize >= 112 && rdesc[104] == 0x26 && rdesc[105] == 0x80 &&
                        rdesc[106] == 0x03) {
                hid_info(hdev, "fixing up Sunplus Wireless Desktop report descriptor\n");
                rdesc[105] = rdesc[110] = 0x03;
index 3e388ec31da84bd5d41b9c6d6771d75ceb2c81a2..f0db7eca902324b84bf97ad915edd05d0c6a35a4 100644 (file)
@@ -1416,6 +1416,7 @@ static void wacom_remove(struct hid_device *hdev)
        kfree(wacom);
 }
 
+#ifdef CONFIG_PM
 static int wacom_resume(struct hid_device *hdev)
 {
        struct wacom *wacom = hid_get_drvdata(hdev);
@@ -1436,6 +1437,7 @@ static int wacom_reset_resume(struct hid_device *hdev)
 {
        return wacom_resume(hdev);
 }
+#endif /* CONFIG_PM */
 
 static struct hid_driver wacom_driver = {
        .name =         "wacom",
index fc6f5d54e7f755282025045f843ba62dcff68fa9..8890870309e4db7f5f875c202756006b3323538b 100644 (file)
@@ -309,6 +309,7 @@ static ssize_t set_convrate(struct device *dev, struct device_attribute *da,
        data->conf |= (resol << DS1621_REG_CONFIG_RESOL_SHIFT);
        i2c_smbus_write_byte_data(client, DS1621_REG_CONF, data->conf);
        data->update_interval = ds1721_convrates[resol];
+       data->zbits = 7 - resol;
        mutex_unlock(&data->update_lock);
 
        return count;
index 3e3b680dc007319cf14abe35e5a26fc7f7c8a2b4..b51a402752c4c616a0d2a57ba6cd73c983296fc1 100644 (file)
@@ -23,17 +23,14 @@ config I2C
          This I2C support can also be built as a module.  If so, the module
          will be called i2c-core.
 
-config I2C_ACPI
-       bool "I2C ACPI support"
-       select I2C
-       depends on ACPI
+config ACPI_I2C_OPREGION
+       bool "ACPI I2C Operation region support"
+       depends on I2C=y && ACPI
        default y
        help
-         Say Y here if you want to enable ACPI I2C support. This includes support
-         for automatic enumeration of I2C slave devices and support for ACPI I2C
-         Operation Regions. Operation Regions allow firmware (BIOS) code to
-         access I2C slave devices, such as smart batteries through an I2C host
-         controller driver.
+         Say Y here if you want to enable ACPI I2C operation region support.
+         Operation Regions allow firmware (BIOS) code to access I2C slave devices,
+         such as smart batteries through an I2C host controller driver.
 
 if I2C
 
index a1f590cbb435d4c83a507beb4c11a051a77d828e..e0228b228256a8771df7b0be2536c3c42f90448d 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 i2ccore-y := i2c-core.o
-i2ccore-$(CONFIG_I2C_ACPI)     += i2c-acpi.o
+i2ccore-$(CONFIG_ACPI)         += i2c-acpi.o
 
 obj-$(CONFIG_I2C_BOARDINFO)    += i2c-boardinfo.o
 obj-$(CONFIG_I2C)              += i2ccore.o
index 79a68999a6962914f93106b4fc9154129b9071f0..917d54588d95c14f966abd326e12467bea244342 100644 (file)
@@ -101,6 +101,7 @@ struct at91_twi_dev {
        unsigned twi_cwgr_reg;
        struct at91_twi_pdata *pdata;
        bool use_dma;
+       bool recv_len_abort;
        struct at91_twi_dma dma;
 };
 
@@ -267,12 +268,24 @@ static void at91_twi_read_next_byte(struct at91_twi_dev *dev)
        *dev->buf = at91_twi_read(dev, AT91_TWI_RHR) & 0xff;
        --dev->buf_len;
 
+       /* return if aborting, we only needed to read RHR to clear RXRDY*/
+       if (dev->recv_len_abort)
+               return;
+
        /* handle I2C_SMBUS_BLOCK_DATA */
        if (unlikely(dev->msg->flags & I2C_M_RECV_LEN)) {
-               dev->msg->flags &= ~I2C_M_RECV_LEN;
-               dev->buf_len += *dev->buf;
-               dev->msg->len = dev->buf_len + 1;
-               dev_dbg(dev->dev, "received block length %d\n", dev->buf_len);
+               /* ensure length byte is a valid value */
+               if (*dev->buf <= I2C_SMBUS_BLOCK_MAX && *dev->buf > 0) {
+                       dev->msg->flags &= ~I2C_M_RECV_LEN;
+                       dev->buf_len += *dev->buf;
+                       dev->msg->len = dev->buf_len + 1;
+                       dev_dbg(dev->dev, "received block length %d\n",
+                                        dev->buf_len);
+               } else {
+                       /* abort and send the stop by reading one more byte */
+                       dev->recv_len_abort = true;
+                       dev->buf_len = 1;
+               }
        }
 
        /* send stop if second but last byte has been read */
@@ -421,8 +434,8 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev)
                }
        }
 
-       ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
-                                                       dev->adapter.timeout);
+       ret = wait_for_completion_io_timeout(&dev->cmd_complete,
+                                            dev->adapter.timeout);
        if (ret == 0) {
                dev_err(dev->dev, "controller timed out\n");
                at91_init_twi_bus(dev);
@@ -444,6 +457,12 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev)
                ret = -EIO;
                goto error;
        }
+       if (dev->recv_len_abort) {
+               dev_err(dev->dev, "invalid smbus block length recvd\n");
+               ret = -EPROTO;
+               goto error;
+       }
+
        dev_dbg(dev->dev, "transfer complete\n");
 
        return 0;
@@ -500,6 +519,7 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num)
        dev->buf_len = m_start->len;
        dev->buf = m_start->buf;
        dev->msg = m_start;
+       dev->recv_len_abort = false;
 
        ret = at91_do_twi_transfer(dev);
 
index 2994690b26e9b18ffc6223df4db9d8d489924079..10467a3277492a6fa98ee597e7b1b33df687ec32 100644 (file)
 
 /* Older devices have their ID defined in <linux/pci_ids.h> */
 #define PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS             0x0f12
+#define PCI_DEVICE_ID_INTEL_BRASWELL_SMBUS             0x2292
 #define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS          0x1c22
 #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS             0x1d22
 /* Patsburg also has three 'Integrated Device Function' SMBus controllers */
@@ -828,6 +829,7 @@ static const struct pci_device_id i801_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WILDCATPOINT_SMBUS) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BRASWELL_SMBUS) },
        { 0, }
 };
 
index 6dc5ded86f6262e8b9eb4bceeae83e4d8eafd4e9..2f64273d3f2bba63c8f930e66fad83fdf5750551 100644 (file)
@@ -746,8 +746,7 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
        }
        tclk = clk_get_rate(drv_data->clk);
 
-       rc = of_property_read_u32(np, "clock-frequency", &bus_freq);
-       if (rc)
+       if (of_property_read_u32(np, "clock-frequency", &bus_freq))
                bus_freq = 100000; /* 100kHz by default */
 
        if (!mv64xxx_find_baud_factors(bus_freq, tclk,
index f3c7139dfa251f51b6c67da1b9f2de869fb6860d..1cc146cfc1f3dce02d4d83c7e79b698f07b161c9 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/slab.h>
+#include <linux/spinlock.h>
 
 /* register offsets */
 #define ICSCR  0x00    /* slave ctrl */
@@ -95,6 +96,7 @@ struct rcar_i2c_priv {
        struct i2c_msg  *msg;
        struct clk *clk;
 
+       spinlock_t lock;
        wait_queue_head_t wait;
 
        int pos;
@@ -365,20 +367,20 @@ static irqreturn_t rcar_i2c_irq(int irq, void *ptr)
        struct rcar_i2c_priv *priv = ptr;
        u32 msr;
 
+       /*-------------- spin lock -----------------*/
+       spin_lock(&priv->lock);
+
        msr = rcar_i2c_read(priv, ICMSR);
 
+       /* Only handle interrupts that are currently enabled */
+       msr &= rcar_i2c_read(priv, ICMIER);
+
        /* Arbitration lost */
        if (msr & MAL) {
                rcar_i2c_flags_set(priv, (ID_DONE | ID_ARBLOST));
                goto out;
        }
 
-       /* Stop */
-       if (msr & MST) {
-               rcar_i2c_flags_set(priv, ID_DONE);
-               goto out;
-       }
-
        /* Nack */
        if (msr & MNR) {
                /* go to stop phase */
@@ -388,6 +390,12 @@ static irqreturn_t rcar_i2c_irq(int irq, void *ptr)
                goto out;
        }
 
+       /* Stop */
+       if (msr & MST) {
+               rcar_i2c_flags_set(priv, ID_DONE);
+               goto out;
+       }
+
        if (rcar_i2c_is_recv(priv))
                rcar_i2c_flags_set(priv, rcar_i2c_irq_recv(priv, msr));
        else
@@ -400,6 +408,9 @@ out:
                wake_up(&priv->wait);
        }
 
+       spin_unlock(&priv->lock);
+       /*-------------- spin unlock -----------------*/
+
        return IRQ_HANDLED;
 }
 
@@ -409,14 +420,21 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
 {
        struct rcar_i2c_priv *priv = i2c_get_adapdata(adap);
        struct device *dev = rcar_i2c_priv_to_dev(priv);
+       unsigned long flags;
        int i, ret, timeout;
 
        pm_runtime_get_sync(dev);
 
+       /*-------------- spin lock -----------------*/
+       spin_lock_irqsave(&priv->lock, flags);
+
        rcar_i2c_init(priv);
        /* start clock */
        rcar_i2c_write(priv, ICCCR, priv->icccr);
 
+       spin_unlock_irqrestore(&priv->lock, flags);
+       /*-------------- spin unlock -----------------*/
+
        ret = rcar_i2c_bus_barrier(priv);
        if (ret < 0)
                goto out;
@@ -428,6 +446,9 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
                        break;
                }
 
+               /*-------------- spin lock -----------------*/
+               spin_lock_irqsave(&priv->lock, flags);
+
                /* init each data */
                priv->msg       = &msgs[i];
                priv->pos       = 0;
@@ -437,6 +458,9 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
 
                ret = rcar_i2c_prepare_msg(priv);
 
+               spin_unlock_irqrestore(&priv->lock, flags);
+               /*-------------- spin unlock -----------------*/
+
                if (ret < 0)
                        break;
 
@@ -540,6 +564,7 @@ static int rcar_i2c_probe(struct platform_device *pdev)
 
        irq = platform_get_irq(pdev, 0);
        init_waitqueue_head(&priv->wait);
+       spin_lock_init(&priv->lock);
 
        adap = &priv->adap;
        adap->nr = pdev->id;
index 69e11853e8bff187e09459167506ec24b8f7a122..e637c32ae5172bcaa77bdd2c5eda8dee34457176 100644 (file)
@@ -323,6 +323,10 @@ static void rk3x_i2c_handle_read(struct rk3x_i2c *i2c, unsigned int ipd)
        /* ack interrupt */
        i2c_writel(i2c, REG_INT_MBRF, REG_IPD);
 
+       /* Can only handle a maximum of 32 bytes at a time */
+       if (len > 32)
+               len = 32;
+
        /* read the data from receive buffer */
        for (i = 0; i < len; ++i) {
                if (i % 4 == 0)
index e8b61967334bb199cbd551042820647d11aea62f..0dbc18c15c43a8529b4c84a34650887cc7a56019 100644 (file)
@@ -126,6 +126,7 @@ void acpi_i2c_register_devices(struct i2c_adapter *adap)
                dev_warn(&adap->dev, "failed to enumerate I2C slaves\n");
 }
 
+#ifdef CONFIG_ACPI_I2C_OPREGION
 static int acpi_gsb_i2c_read_bytes(struct i2c_client *client,
                u8 cmd, u8 *data, u8 data_len)
 {
@@ -360,3 +361,4 @@ void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter)
 
        acpi_bus_detach_private_data(handle);
 }
+#endif
index 4d140bbbe1006c172cecd2fd5313778e8eb5db17..9b7ee7e427df4f3b84cf611cf0fb0965d6a5db58 100644 (file)
@@ -89,6 +89,7 @@ struct idle_cpu {
         * Indicate which enable bits to clear here.
         */
        unsigned long auto_demotion_disable_flags;
+       bool byt_auto_demotion_disable_flag;
        bool disable_promotion_to_c1e;
 };
 
@@ -442,6 +443,66 @@ static struct cpuidle_state hsw_cstates[] = {
        {
                .enter = NULL }
 };
+static struct cpuidle_state bdw_cstates[] = {
+       {
+               .name = "C1-BDW",
+               .desc = "MWAIT 0x00",
+               .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID,
+               .exit_latency = 2,
+               .target_residency = 2,
+               .enter = &intel_idle },
+       {
+               .name = "C1E-BDW",
+               .desc = "MWAIT 0x01",
+               .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_TIME_VALID,
+               .exit_latency = 10,
+               .target_residency = 20,
+               .enter = &intel_idle },
+       {
+               .name = "C3-BDW",
+               .desc = "MWAIT 0x10",
+               .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+               .exit_latency = 40,
+               .target_residency = 100,
+               .enter = &intel_idle },
+       {
+               .name = "C6-BDW",
+               .desc = "MWAIT 0x20",
+               .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+               .exit_latency = 133,
+               .target_residency = 400,
+               .enter = &intel_idle },
+       {
+               .name = "C7s-BDW",
+               .desc = "MWAIT 0x32",
+               .flags = MWAIT2flg(0x32) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+               .exit_latency = 166,
+               .target_residency = 500,
+               .enter = &intel_idle },
+       {
+               .name = "C8-BDW",
+               .desc = "MWAIT 0x40",
+               .flags = MWAIT2flg(0x40) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+               .exit_latency = 300,
+               .target_residency = 900,
+               .enter = &intel_idle },
+       {
+               .name = "C9-BDW",
+               .desc = "MWAIT 0x50",
+               .flags = MWAIT2flg(0x50) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+               .exit_latency = 600,
+               .target_residency = 1800,
+               .enter = &intel_idle },
+       {
+               .name = "C10-BDW",
+               .desc = "MWAIT 0x60",
+               .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+               .exit_latency = 2600,
+               .target_residency = 7700,
+               .enter = &intel_idle },
+       {
+               .enter = NULL }
+};
 
 static struct cpuidle_state atom_cstates[] = {
        {
@@ -613,6 +674,7 @@ static const struct idle_cpu idle_cpu_snb = {
 static const struct idle_cpu idle_cpu_byt = {
        .state_table = byt_cstates,
        .disable_promotion_to_c1e = true,
+       .byt_auto_demotion_disable_flag = true,
 };
 
 static const struct idle_cpu idle_cpu_ivb = {
@@ -630,6 +692,11 @@ static const struct idle_cpu idle_cpu_hsw = {
        .disable_promotion_to_c1e = true,
 };
 
+static const struct idle_cpu idle_cpu_bdw = {
+       .state_table = bdw_cstates,
+       .disable_promotion_to_c1e = true,
+};
+
 static const struct idle_cpu idle_cpu_avn = {
        .state_table = avn_cstates,
        .disable_promotion_to_c1e = true,
@@ -658,7 +725,10 @@ static const struct x86_cpu_id intel_idle_ids[] = {
        ICPU(0x3f, idle_cpu_hsw),
        ICPU(0x45, idle_cpu_hsw),
        ICPU(0x46, idle_cpu_hsw),
-       ICPU(0x4D, idle_cpu_avn),
+       ICPU(0x4d, idle_cpu_avn),
+       ICPU(0x3d, idle_cpu_bdw),
+       ICPU(0x4f, idle_cpu_bdw),
+       ICPU(0x56, idle_cpu_bdw),
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, intel_idle_ids);
@@ -814,6 +884,11 @@ static int __init intel_idle_cpuidle_driver_init(void)
        if (icpu->auto_demotion_disable_flags)
                on_each_cpu(auto_demotion_disable, NULL, 1);
 
+       if (icpu->byt_auto_demotion_disable_flag) {
+               wrmsrl(MSR_CC6_DEMOTION_POLICY_CONFIG, 0);
+               wrmsrl(MSR_MC6_DEMOTION_POLICY_CONFIG, 0);
+       }
+
        if (icpu->disable_promotion_to_c1e)     /* each-cpu is redundant */
                on_each_cpu(c1e_promotion_disable, NULL, 1);
 
index e1e558a3d692bbd8b907a84efe222481b0ae1a8e..af8256353c7de6a9449f3da753b4b07e8df025fc 100644 (file)
@@ -1089,6 +1089,30 @@ static int __mlx4_ib_destroy_flow(struct mlx4_dev *dev, u64 reg_id)
        return err;
 }
 
+static int mlx4_ib_tunnel_steer_add(struct ib_qp *qp, struct ib_flow_attr *flow_attr,
+                                   u64 *reg_id)
+{
+       void *ib_flow;
+       union ib_flow_spec *ib_spec;
+       struct mlx4_dev *dev = to_mdev(qp->device)->dev;
+       int err = 0;
+
+       if (dev->caps.tunnel_offload_mode != MLX4_TUNNEL_OFFLOAD_MODE_VXLAN)
+               return 0; /* do nothing */
+
+       ib_flow = flow_attr + 1;
+       ib_spec = (union ib_flow_spec *)ib_flow;
+
+       if (ib_spec->type !=  IB_FLOW_SPEC_ETH || flow_attr->num_of_specs != 1)
+               return 0; /* do nothing */
+
+       err = mlx4_tunnel_steer_add(to_mdev(qp->device)->dev, ib_spec->eth.val.dst_mac,
+                                   flow_attr->port, qp->qp_num,
+                                   MLX4_DOMAIN_UVERBS | (flow_attr->priority & 0xff),
+                                   reg_id);
+       return err;
+}
+
 static struct ib_flow *mlx4_ib_create_flow(struct ib_qp *qp,
                                    struct ib_flow_attr *flow_attr,
                                    int domain)
@@ -1136,6 +1160,12 @@ static struct ib_flow *mlx4_ib_create_flow(struct ib_qp *qp,
                i++;
        }
 
+       if (i < ARRAY_SIZE(type) && flow_attr->type == IB_FLOW_ATTR_NORMAL) {
+               err = mlx4_ib_tunnel_steer_add(qp, flow_attr, &mflow->reg_id[i]);
+               if (err)
+                       goto err_free;
+       }
+
        return &mflow->ibflow;
 
 err_free:
index 67780452f0cfb85d72fc98bfd0faefbe005fb32a..efb9eff8906c34845053ba04ced5dea9bfe8cbe4 100644 (file)
@@ -1677,9 +1677,15 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
                }
        }
 
-       if (qp->ibqp.qp_type == IB_QPT_RAW_PACKET)
+       if (qp->ibqp.qp_type == IB_QPT_RAW_PACKET) {
                context->pri_path.ackto = (context->pri_path.ackto & 0xf8) |
                                        MLX4_IB_LINK_TYPE_ETH;
+               if (dev->dev->caps.tunnel_offload_mode ==  MLX4_TUNNEL_OFFLOAD_MODE_VXLAN) {
+                       /* set QP to receive both tunneled & non-tunneled packets */
+                       if (!(context->flags & (1 << MLX4_RSS_QPC_FLAG_OFFSET)))
+                               context->srqn = cpu_to_be32(7 << 28);
+               }
+       }
 
        if (ibqp->qp_type == IB_QPT_UD && (new_state == IB_QPS_RTR)) {
                int is_eth = rdma_port_get_link_layer(
index d398f1321f143f834e5ddc70563ed368ca130c24..fbe29fcb15c5b85d27c5e001df59fe20d144b577 100644 (file)
@@ -236,6 +236,35 @@ void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count)
 }
 EXPORT_SYMBOL(input_mt_report_pointer_emulation);
 
+static void __input_mt_drop_unused(struct input_dev *dev, struct input_mt *mt)
+{
+       int i;
+
+       for (i = 0; i < mt->num_slots; i++) {
+               if (!input_mt_is_used(mt, &mt->slots[i])) {
+                       input_mt_slot(dev, i);
+                       input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
+               }
+       }
+}
+
+/**
+ * input_mt_drop_unused() - Inactivate slots not seen in this frame
+ * @dev: input device with allocated MT slots
+ *
+ * Lift all slots not seen since the last call to this function.
+ */
+void input_mt_drop_unused(struct input_dev *dev)
+{
+       struct input_mt *mt = dev->mt;
+
+       if (mt) {
+               __input_mt_drop_unused(dev, mt);
+               mt->frame++;
+       }
+}
+EXPORT_SYMBOL(input_mt_drop_unused);
+
 /**
  * input_mt_sync_frame() - synchronize mt frame
  * @dev: input device with allocated MT slots
@@ -247,20 +276,13 @@ EXPORT_SYMBOL(input_mt_report_pointer_emulation);
 void input_mt_sync_frame(struct input_dev *dev)
 {
        struct input_mt *mt = dev->mt;
-       struct input_mt_slot *s;
        bool use_count = false;
 
        if (!mt)
                return;
 
-       if (mt->flags & INPUT_MT_DROP_UNUSED) {
-               for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
-                       if (input_mt_is_used(mt, s))
-                               continue;
-                       input_mt_slot(dev, s - mt->slots);
-                       input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
-               }
-       }
+       if (mt->flags & INPUT_MT_DROP_UNUSED)
+               __input_mt_drop_unused(dev, mt);
 
        if ((mt->flags & INPUT_MT_POINTER) && !(mt->flags & INPUT_MT_SEMI_MT))
                use_count = true;
index 9135606c86496511919a5238898aa98cf1c74996..ab0fdcd36e18d7746ce7f8d5e41c51b5dfae9304 100644 (file)
@@ -158,7 +158,7 @@ static unsigned int get_time_pit(void)
 #define GET_TIME(x)    rdtscl(x)
 #define DELTA(x,y)     ((y)-(x))
 #define TIME_NAME      "TSC"
-#elif defined(__alpha__) || defined(CONFIG_MN10300) || defined(CONFIG_ARM) || defined(CONFIG_TILE)
+#elif defined(__alpha__) || defined(CONFIG_MN10300) || defined(CONFIG_ARM) || defined(CONFIG_ARM64) || defined(CONFIG_TILE)
 #define GET_TIME(x)    do { x = get_cycles(); } while (0)
 #define DELTA(x,y)     ((y)-(x))
 #define TIME_NAME      "get_cycles"
index 603fe0dd3682f7cd5baa859de39f37e2253825d9..177602cf7079a41edf22553d348400d8035e649a 100644 (file)
@@ -95,7 +95,8 @@
 #define XTYPE_XBOX        0
 #define XTYPE_XBOX360     1
 #define XTYPE_XBOX360W    2
-#define XTYPE_UNKNOWN     3
+#define XTYPE_XBOXONE     3
+#define XTYPE_UNKNOWN     4
 
 static bool dpad_to_buttons;
 module_param(dpad_to_buttons, bool, S_IRUGO);
@@ -121,6 +122,7 @@ static const struct xpad_device {
        { 0x045e, 0x0287, "Microsoft Xbox Controller S", 0, XTYPE_XBOX },
        { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", 0, XTYPE_XBOX },
        { 0x045e, 0x028e, "Microsoft X-Box 360 pad", 0, XTYPE_XBOX360 },
+       { 0x045e, 0x02d1, "Microsoft X-Box One pad", 0, XTYPE_XBOXONE },
        { 0x045e, 0x0291, "Xbox 360 Wireless Receiver (XBOX)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
        { 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
        { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX },
@@ -231,10 +233,12 @@ static const signed short xpad_abs_triggers[] = {
        -1
 };
 
-/* Xbox 360 has a vendor-specific class, so we cannot match it with only
+/*
+ * Xbox 360 has a vendor-specific class, so we cannot match it with only
  * USB_INTERFACE_INFO (also specifically refused by USB subsystem), so we
  * match against vendor id as well. Wired Xbox 360 devices have protocol 1,
- * wireless controllers have protocol 129. */
+ * wireless controllers have protocol 129.
+ */
 #define XPAD_XBOX360_VENDOR_PROTOCOL(vend,pr) \
        .match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO, \
        .idVendor = (vend), \
@@ -245,9 +249,20 @@ static const signed short xpad_abs_triggers[] = {
        { XPAD_XBOX360_VENDOR_PROTOCOL(vend,1) }, \
        { XPAD_XBOX360_VENDOR_PROTOCOL(vend,129) }
 
+/* The Xbox One controller uses subclass 71 and protocol 208. */
+#define XPAD_XBOXONE_VENDOR_PROTOCOL(vend, pr) \
+       .match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO, \
+       .idVendor = (vend), \
+       .bInterfaceClass = USB_CLASS_VENDOR_SPEC, \
+       .bInterfaceSubClass = 71, \
+       .bInterfaceProtocol = (pr)
+#define XPAD_XBOXONE_VENDOR(vend) \
+       { XPAD_XBOXONE_VENDOR_PROTOCOL(vend, 208) }
+
 static struct usb_device_id xpad_table[] = {
        { USB_INTERFACE_INFO('X', 'B', 0) },    /* X-Box USB-IF not approved class */
        XPAD_XBOX360_VENDOR(0x045e),            /* Microsoft X-Box 360 controllers */
+       XPAD_XBOXONE_VENDOR(0x045e),            /* Microsoft X-Box One controllers */
        XPAD_XBOX360_VENDOR(0x046d),            /* Logitech X-Box 360 style controllers */
        XPAD_XBOX360_VENDOR(0x0738),            /* Mad Catz X-Box 360 controllers */
        { USB_DEVICE(0x0738, 0x4540) },         /* Mad Catz Beat Pad */
@@ -278,12 +293,10 @@ struct usb_xpad {
        struct urb *bulk_out;
        unsigned char *bdata;
 
-#if defined(CONFIG_JOYSTICK_XPAD_FF) || defined(CONFIG_JOYSTICK_XPAD_LEDS)
        struct urb *irq_out;            /* urb for interrupt out report */
        unsigned char *odata;           /* output data */
        dma_addr_t odata_dma;
        struct mutex odata_mutex;
-#endif
 
 #if defined(CONFIG_JOYSTICK_XPAD_LEDS)
        struct xpad_led *led;
@@ -470,6 +483,105 @@ static void xpad360w_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned cha
        xpad360_process_packet(xpad, cmd, &data[4]);
 }
 
+/*
+ *     xpadone_process_buttons
+ *
+ *     Process a button update packet from an Xbox one controller.
+ */
+static void xpadone_process_buttons(struct usb_xpad *xpad,
+                               struct input_dev *dev,
+                               unsigned char *data)
+{
+       /* menu/view buttons */
+       input_report_key(dev, BTN_START,  data[4] & 0x04);
+       input_report_key(dev, BTN_SELECT, data[4] & 0x08);
+
+       /* buttons A,B,X,Y */
+       input_report_key(dev, BTN_A,    data[4] & 0x10);
+       input_report_key(dev, BTN_B,    data[4] & 0x20);
+       input_report_key(dev, BTN_X,    data[4] & 0x40);
+       input_report_key(dev, BTN_Y,    data[4] & 0x80);
+
+       /* digital pad */
+       if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
+               /* dpad as buttons (left, right, up, down) */
+               input_report_key(dev, BTN_TRIGGER_HAPPY1, data[5] & 0x04);
+               input_report_key(dev, BTN_TRIGGER_HAPPY2, data[5] & 0x08);
+               input_report_key(dev, BTN_TRIGGER_HAPPY3, data[5] & 0x01);
+               input_report_key(dev, BTN_TRIGGER_HAPPY4, data[5] & 0x02);
+       } else {
+               input_report_abs(dev, ABS_HAT0X,
+                                !!(data[5] & 0x08) - !!(data[5] & 0x04));
+               input_report_abs(dev, ABS_HAT0Y,
+                                !!(data[5] & 0x02) - !!(data[5] & 0x01));
+       }
+
+       /* TL/TR */
+       input_report_key(dev, BTN_TL,   data[5] & 0x10);
+       input_report_key(dev, BTN_TR,   data[5] & 0x20);
+
+       /* stick press left/right */
+       input_report_key(dev, BTN_THUMBL, data[5] & 0x40);
+       input_report_key(dev, BTN_THUMBR, data[5] & 0x80);
+
+       if (!(xpad->mapping & MAP_STICKS_TO_NULL)) {
+               /* left stick */
+               input_report_abs(dev, ABS_X,
+                                (__s16) le16_to_cpup((__le16 *)(data + 10)));
+               input_report_abs(dev, ABS_Y,
+                                ~(__s16) le16_to_cpup((__le16 *)(data + 12)));
+
+               /* right stick */
+               input_report_abs(dev, ABS_RX,
+                                (__s16) le16_to_cpup((__le16 *)(data + 14)));
+               input_report_abs(dev, ABS_RY,
+                                ~(__s16) le16_to_cpup((__le16 *)(data + 16)));
+       }
+
+       /* triggers left/right */
+       if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) {
+               input_report_key(dev, BTN_TL2,
+                                (__u16) le16_to_cpup((__le16 *)(data + 6)));
+               input_report_key(dev, BTN_TR2,
+                                (__u16) le16_to_cpup((__le16 *)(data + 8)));
+       } else {
+               input_report_abs(dev, ABS_Z,
+                                (__u16) le16_to_cpup((__le16 *)(data + 6)));
+               input_report_abs(dev, ABS_RZ,
+                                (__u16) le16_to_cpup((__le16 *)(data + 8)));
+       }
+
+       input_sync(dev);
+}
+
+/*
+ *     xpadone_process_packet
+ *
+ *     Completes a request by converting the data into events for the
+ *     input subsystem. This version is for the Xbox One controller.
+ *
+ *     The report format was gleaned from
+ *     https://github.com/kylelemons/xbox/blob/master/xbox.go
+ */
+
+static void xpadone_process_packet(struct usb_xpad *xpad,
+                               u16 cmd, unsigned char *data)
+{
+       struct input_dev *dev = xpad->dev;
+
+       switch (data[0]) {
+       case 0x20:
+               xpadone_process_buttons(xpad, dev, data);
+               break;
+
+       case 0x07:
+               /* the xbox button has its own special report */
+               input_report_key(dev, BTN_MODE, data[4] & 0x01);
+               input_sync(dev);
+               break;
+       }
+}
+
 static void xpad_irq_in(struct urb *urb)
 {
        struct usb_xpad *xpad = urb->context;
@@ -502,6 +614,9 @@ static void xpad_irq_in(struct urb *urb)
        case XTYPE_XBOX360W:
                xpad360w_process_packet(xpad, 0, xpad->idata);
                break;
+       case XTYPE_XBOXONE:
+               xpadone_process_packet(xpad, 0, xpad->idata);
+               break;
        default:
                xpad_process_packet(xpad, 0, xpad->idata);
        }
@@ -535,7 +650,6 @@ static void xpad_bulk_out(struct urb *urb)
        }
 }
 
-#if defined(CONFIG_JOYSTICK_XPAD_FF) || defined(CONFIG_JOYSTICK_XPAD_LEDS)
 static void xpad_irq_out(struct urb *urb)
 {
        struct usb_xpad *xpad = urb->context;
@@ -573,6 +687,7 @@ exit:
 static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
 {
        struct usb_endpoint_descriptor *ep_irq_out;
+       int ep_irq_out_idx;
        int error;
 
        if (xpad->xtype == XTYPE_UNKNOWN)
@@ -593,7 +708,10 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
                goto fail2;
        }
 
-       ep_irq_out = &intf->cur_altsetting->endpoint[1].desc;
+       /* Xbox One controller has in/out endpoints swapped. */
+       ep_irq_out_idx = xpad->xtype == XTYPE_XBOXONE ? 0 : 1;
+       ep_irq_out = &intf->cur_altsetting->endpoint[ep_irq_out_idx].desc;
+
        usb_fill_int_urb(xpad->irq_out, xpad->udev,
                         usb_sndintpipe(xpad->udev, ep_irq_out->bEndpointAddress),
                         xpad->odata, XPAD_PKT_LEN,
@@ -621,11 +739,6 @@ static void xpad_deinit_output(struct usb_xpad *xpad)
                                xpad->odata, xpad->odata_dma);
        }
 }
-#else
-static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) { return 0; }
-static void xpad_deinit_output(struct usb_xpad *xpad) {}
-static void xpad_stop_output(struct usb_xpad *xpad) {}
-#endif
 
 #ifdef CONFIG_JOYSTICK_XPAD_FF
 static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect *effect)
@@ -692,7 +805,7 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect
 
 static int xpad_init_ff(struct usb_xpad *xpad)
 {
-       if (xpad->xtype == XTYPE_UNKNOWN)
+       if (xpad->xtype == XTYPE_UNKNOWN || xpad->xtype == XTYPE_XBOXONE)
                return 0;
 
        input_set_capability(xpad->dev, EV_FF, FF_RUMBLE);
@@ -801,6 +914,14 @@ static int xpad_open(struct input_dev *dev)
        if (usb_submit_urb(xpad->irq_in, GFP_KERNEL))
                return -EIO;
 
+       if (xpad->xtype == XTYPE_XBOXONE) {
+               /* Xbox one controller needs to be initialized. */
+               xpad->odata[0] = 0x05;
+               xpad->odata[1] = 0x20;
+               xpad->irq_out->transfer_buffer_length = 2;
+               return usb_submit_urb(xpad->irq_out, GFP_KERNEL);
+       }
+
        return 0;
 }
 
@@ -816,6 +937,7 @@ static void xpad_close(struct input_dev *dev)
 
 static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs)
 {
+       struct usb_xpad *xpad = input_get_drvdata(input_dev);
        set_bit(abs, input_dev->absbit);
 
        switch (abs) {
@@ -827,7 +949,10 @@ static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs)
                break;
        case ABS_Z:
        case ABS_RZ:    /* the triggers (if mapped to axes) */
-               input_set_abs_params(input_dev, abs, 0, 255, 0, 0);
+               if (xpad->xtype == XTYPE_XBOXONE)
+                       input_set_abs_params(input_dev, abs, 0, 1023, 0, 0);
+               else
+                       input_set_abs_params(input_dev, abs, 0, 255, 0, 0);
                break;
        case ABS_HAT0X:
        case ABS_HAT0Y: /* the d-pad (only if dpad is mapped to axes */
@@ -842,6 +967,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
        struct usb_xpad *xpad;
        struct input_dev *input_dev;
        struct usb_endpoint_descriptor *ep_irq_in;
+       int ep_irq_in_idx;
        int i, error;
 
        for (i = 0; xpad_device[i].idVendor; i++) {
@@ -850,6 +976,16 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
                        break;
        }
 
+       if (xpad_device[i].xtype == XTYPE_XBOXONE &&
+           intf->cur_altsetting->desc.bInterfaceNumber != 0) {
+               /*
+                * The Xbox One controller lists three interfaces all with the
+                * same interface class, subclass and protocol. Differentiate by
+                * interface number.
+                */
+               return -ENODEV;
+       }
+
        xpad = kzalloc(sizeof(struct usb_xpad), GFP_KERNEL);
        input_dev = input_allocate_device();
        if (!xpad || !input_dev) {
@@ -920,7 +1056,8 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
                __set_bit(xpad_common_btn[i], input_dev->keybit);
 
        /* set up model-specific ones */
-       if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX360W) {
+       if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX360W ||
+           xpad->xtype == XTYPE_XBOXONE) {
                for (i = 0; xpad360_btn[i] >= 0; i++)
                        __set_bit(xpad360_btn[i], input_dev->keybit);
        } else {
@@ -933,7 +1070,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
                        __set_bit(xpad_btn_pad[i], input_dev->keybit);
        } else {
                for (i = 0; xpad_abs_pad[i] >= 0; i++)
-                   xpad_set_up_abs(input_dev, xpad_abs_pad[i]);
+                       xpad_set_up_abs(input_dev, xpad_abs_pad[i]);
        }
 
        if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) {
@@ -956,7 +1093,10 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
        if (error)
                goto fail5;
 
-       ep_irq_in = &intf->cur_altsetting->endpoint[0].desc;
+       /* Xbox One controller has in/out endpoints swapped. */
+       ep_irq_in_idx = xpad->xtype == XTYPE_XBOXONE ? 1 : 0;
+       ep_irq_in = &intf->cur_altsetting->endpoint[ep_irq_in_idx].desc;
+
        usb_fill_int_urb(xpad->irq_in, udev,
                         usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress),
                         xpad->idata, XPAD_PKT_LEN, xpad_irq_in,
index f7d7a0d4ab4ec5a7378f061d6d10e70085245625..180b184ab90f31935e1fa9c71bd7eb8fa4e68593 100644 (file)
@@ -64,7 +64,7 @@ struct cap1106_priv {
        struct input_dev *idev;
 
        /* config */
-       unsigned int keycodes[CAP1106_NUM_CHN];
+       unsigned short keycodes[CAP1106_NUM_CHN];
 };
 
 static const struct reg_default cap1106_reg_defaults[] = {
@@ -272,6 +272,12 @@ static int cap1106_i2c_probe(struct i2c_client *i2c_client,
        for (i = 0; i < CAP1106_NUM_CHN; i++)
                __set_bit(priv->keycodes[i], priv->idev->keybit);
 
+       __clear_bit(KEY_RESERVED, priv->idev->keybit);
+
+       priv->idev->keycode = priv->keycodes;
+       priv->idev->keycodesize = sizeof(priv->keycodes[0]);
+       priv->idev->keycodemax = ARRAY_SIZE(priv->keycodes);
+
        priv->idev->id.vendor = CAP1106_MANUFACTURER_ID;
        priv->idev->id.product = CAP1106_PRODUCT_ID;
        priv->idev->id.version = rev;
index a59a1a64b6746745522e1da15e541008d738fcca..a956b980ee73f16fb8eeeae2c9f19bbce0e049f9 100644 (file)
@@ -2234,8 +2234,8 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
                return 0;
        }
 
-       psmouse_info(psmouse,
-                    "Unknown ALPS touchpad: E7=%3ph, EC=%3ph\n", e7, ec);
+       psmouse_dbg(psmouse,
+                   "Likely not an ALPS touchpad: E7=%3ph, EC=%3ph\n", e7, ec);
 
        return -EINVAL;
 }
index ee2a04d90d20c1bfe1fd785350119a44eb835109..da51738eb59e712067cd5d4db8b85a3e112739fa 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/input/mt.h>
 #include <linux/serio.h>
 #include <linux/libps2.h>
+#include <asm/unaligned.h>
 #include "psmouse.h"
 #include "elantech.h"
 
@@ -403,6 +404,68 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse)
        input_sync(dev);
 }
 
+static void elantech_report_trackpoint(struct psmouse *psmouse,
+                                      int packet_type)
+{
+       /*
+        * byte 0:  0   0  sx  sy   0   M   R   L
+        * byte 1:~sx   0   0   0   0   0   0   0
+        * byte 2:~sy   0   0   0   0   0   0   0
+        * byte 3:  0   0 ~sy ~sx   0   1   1   0
+        * byte 4: x7  x6  x5  x4  x3  x2  x1  x0
+        * byte 5: y7  y6  y5  y4  y3  y2  y1  y0
+        *
+        * x and y are written in two's complement spread
+        * over 9 bits with sx/sy the relative top bit and
+        * x7..x0 and y7..y0 the lower bits.
+        * The sign of y is opposite to what the input driver
+        * expects for a relative movement
+        */
+
+       struct elantech_data *etd = psmouse->private;
+       struct input_dev *tp_dev = etd->tp_dev;
+       unsigned char *packet = psmouse->packet;
+       int x, y;
+       u32 t;
+
+       if (dev_WARN_ONCE(&psmouse->ps2dev.serio->dev,
+                         !tp_dev,
+                         psmouse_fmt("Unexpected trackpoint message\n"))) {
+               if (etd->debug == 1)
+                       elantech_packet_dump(psmouse);
+               return;
+       }
+
+       t = get_unaligned_le32(&packet[0]);
+
+       switch (t & ~7U) {
+       case 0x06000030U:
+       case 0x16008020U:
+       case 0x26800010U:
+       case 0x36808000U:
+               x = packet[4] - (int)((packet[1]^0x80) << 1);
+               y = (int)((packet[2]^0x80) << 1) - packet[5];
+
+               input_report_key(tp_dev, BTN_LEFT, packet[0] & 0x01);
+               input_report_key(tp_dev, BTN_RIGHT, packet[0] & 0x02);
+               input_report_key(tp_dev, BTN_MIDDLE, packet[0] & 0x04);
+
+               input_report_rel(tp_dev, REL_X, x);
+               input_report_rel(tp_dev, REL_Y, y);
+
+               input_sync(tp_dev);
+
+               break;
+
+       default:
+               /* Dump unexpected packet sequences if debug=1 (default) */
+               if (etd->debug == 1)
+                       elantech_packet_dump(psmouse);
+
+               break;
+       }
+}
+
 /*
  * Interpret complete data packets and report absolute mode input events for
  * hardware version 3. (12 byte packets for two fingers)
@@ -715,6 +778,8 @@ static int elantech_packet_check_v3(struct psmouse *psmouse)
 
                if ((packet[0] & 0x0c) == 0x0c && (packet[3] & 0xce) == 0x0c)
                        return PACKET_V3_TAIL;
+               if ((packet[3] & 0x0f) == 0x06)
+                       return PACKET_TRACKPOINT;
        }
 
        return PACKET_UNKNOWN;
@@ -791,14 +856,23 @@ static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse)
 
        case 3:
                packet_type = elantech_packet_check_v3(psmouse);
-               /* ignore debounce */
-               if (packet_type == PACKET_DEBOUNCE)
-                       return PSMOUSE_FULL_PACKET;
-
-               if (packet_type == PACKET_UNKNOWN)
+               switch (packet_type) {
+               case PACKET_UNKNOWN:
                        return PSMOUSE_BAD_DATA;
 
-               elantech_report_absolute_v3(psmouse, packet_type);
+               case PACKET_DEBOUNCE:
+                       /* ignore debounce */
+                       break;
+
+               case PACKET_TRACKPOINT:
+                       elantech_report_trackpoint(psmouse, packet_type);
+                       break;
+
+               default:
+                       elantech_report_absolute_v3(psmouse, packet_type);
+                       break;
+               }
+
                break;
 
        case 4:
@@ -1018,8 +1092,10 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse,
  * Asus UX31               0x361f00        20, 15, 0e      clickpad
  * Asus UX32VD             0x361f02        00, 15, 0e      clickpad
  * Avatar AVIU-145A2       0x361f00        ?               clickpad
+ * Fujitsu H730            0x570f00        c0, 14, 0c      3 hw buttons (**)
  * Gigabyte U2442          0x450f01        58, 17, 0c      2 hw buttons
  * Lenovo L430             0x350f02        b9, 15, 0c      2 hw buttons (*)
+ * Lenovo L530             0x350f02        b9, 15, 0c      2 hw buttons (*)
  * Samsung NF210           0x150b00        78, 14, 0a      2 hw buttons
  * Samsung NP770Z5E        0x575f01        10, 15, 0f      clickpad
  * Samsung NP700Z5B        0x361f06        21, 15, 0f      clickpad
@@ -1029,6 +1105,8 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse,
  * Samsung RF710           0x450f00        ?               2 hw buttons
  * System76 Pangolin       0x250f01        ?               2 hw buttons
  * (*) + 3 trackpoint buttons
+ * (**) + 0 trackpoint buttons
+ * Note: Lenovo L430 and Lenovo L430 have the same fw_version/caps
  */
 static void elantech_set_buttonpad_prop(struct psmouse *psmouse)
 {
@@ -1324,6 +1402,10 @@ int elantech_detect(struct psmouse *psmouse, bool set_properties)
  */
 static void elantech_disconnect(struct psmouse *psmouse)
 {
+       struct elantech_data *etd = psmouse->private;
+
+       if (etd->tp_dev)
+               input_unregister_device(etd->tp_dev);
        sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj,
                           &elantech_attr_group);
        kfree(psmouse->private);
@@ -1438,8 +1520,10 @@ static int elantech_set_properties(struct elantech_data *etd)
 int elantech_init(struct psmouse *psmouse)
 {
        struct elantech_data *etd;
-       int i, error;
+       int i;
+       int error = -EINVAL;
        unsigned char param[3];
+       struct input_dev *tp_dev;
 
        psmouse->private = etd = kzalloc(sizeof(struct elantech_data), GFP_KERNEL);
        if (!etd)
@@ -1498,14 +1582,49 @@ int elantech_init(struct psmouse *psmouse)
                goto init_fail;
        }
 
+       /* The MSB indicates the presence of the trackpoint */
+       if ((etd->capabilities[0] & 0x80) == 0x80) {
+               tp_dev = input_allocate_device();
+
+               if (!tp_dev) {
+                       error = -ENOMEM;
+                       goto init_fail_tp_alloc;
+               }
+
+               etd->tp_dev = tp_dev;
+               snprintf(etd->tp_phys, sizeof(etd->tp_phys), "%s/input1",
+                       psmouse->ps2dev.serio->phys);
+               tp_dev->phys = etd->tp_phys;
+               tp_dev->name = "Elantech PS/2 TrackPoint";
+               tp_dev->id.bustype = BUS_I8042;
+               tp_dev->id.vendor  = 0x0002;
+               tp_dev->id.product = PSMOUSE_ELANTECH;
+               tp_dev->id.version = 0x0000;
+               tp_dev->dev.parent = &psmouse->ps2dev.serio->dev;
+               tp_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
+               tp_dev->relbit[BIT_WORD(REL_X)] =
+                       BIT_MASK(REL_X) | BIT_MASK(REL_Y);
+               tp_dev->keybit[BIT_WORD(BTN_LEFT)] =
+                       BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE) |
+                       BIT_MASK(BTN_RIGHT);
+               error = input_register_device(etd->tp_dev);
+               if (error < 0)
+                       goto init_fail_tp_reg;
+       }
+
        psmouse->protocol_handler = elantech_process_byte;
        psmouse->disconnect = elantech_disconnect;
        psmouse->reconnect = elantech_reconnect;
        psmouse->pktsize = etd->hw_version > 1 ? 6 : 4;
 
        return 0;
-
+ init_fail_tp_reg:
+       input_free_device(tp_dev);
+ init_fail_tp_alloc:
+       sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj,
+                          &elantech_attr_group);
  init_fail:
+       psmouse_reset(psmouse);
        kfree(etd);
-       return -1;
+       return error;
 }
index 9e0e2a1f340d52817fc18bf79d849bed6d340932..6f3afec02f03ee0cec8b74cbe13bae6a5cba83c5 100644 (file)
@@ -94,6 +94,7 @@
 #define PACKET_V4_HEAD                 0x05
 #define PACKET_V4_MOTION               0x06
 #define PACKET_V4_STATUS               0x07
+#define PACKET_TRACKPOINT              0x08
 
 /*
  * track up to 5 fingers for v4 hardware
@@ -114,6 +115,8 @@ struct finger_pos {
 };
 
 struct elantech_data {
+       struct input_dev *tp_dev;       /* Relative device for trackpoint */
+       char tp_phys[32];
        unsigned char reg_07;
        unsigned char reg_10;
        unsigned char reg_11;
index ef9e0b8a9aa754b6b49e26b7b050c2a7bcf1f078..e8573c68f77e900e83e054c720443328adfa2f7f 100644 (file)
@@ -117,6 +117,9 @@ void synaptics_reset(struct psmouse *psmouse)
 }
 
 #ifdef CONFIG_MOUSE_PS2_SYNAPTICS
+
+static bool cr48_profile_sensor;
+
 struct min_max_quirk {
        const char * const *pnp_ids;
        int x_min, x_max, y_min, y_max;
@@ -1152,6 +1155,42 @@ static void synaptics_image_sensor_process(struct psmouse *psmouse,
        priv->agm_pending = false;
 }
 
+static void synaptics_profile_sensor_process(struct psmouse *psmouse,
+                                            struct synaptics_hw_state *sgm,
+                                            int num_fingers)
+{
+       struct input_dev *dev = psmouse->dev;
+       struct synaptics_data *priv = psmouse->private;
+       struct synaptics_hw_state *hw[2] = { sgm, &priv->agm };
+       struct input_mt_pos pos[2];
+       int slot[2], nsemi, i;
+
+       nsemi = clamp_val(num_fingers, 0, 2);
+
+       for (i = 0; i < nsemi; i++) {
+               pos[i].x = hw[i]->x;
+               pos[i].y = synaptics_invert_y(hw[i]->y);
+       }
+
+       input_mt_assign_slots(dev, slot, pos, nsemi);
+
+       for (i = 0; i < nsemi; i++) {
+               input_mt_slot(dev, slot[i]);
+               input_mt_report_slot_state(dev, MT_TOOL_FINGER, true);
+               input_report_abs(dev, ABS_MT_POSITION_X, pos[i].x);
+               input_report_abs(dev, ABS_MT_POSITION_Y, pos[i].y);
+               input_report_abs(dev, ABS_MT_PRESSURE, hw[i]->z);
+       }
+
+       input_mt_drop_unused(dev);
+       input_mt_report_pointer_emulation(dev, false);
+       input_mt_report_finger_count(dev, num_fingers);
+
+       synaptics_report_buttons(psmouse, sgm);
+
+       input_sync(dev);
+}
+
 /*
  *  called for each full received packet from the touchpad
  */
@@ -1215,6 +1254,11 @@ static void synaptics_process_packet(struct psmouse *psmouse)
                finger_width = 0;
        }
 
+       if (cr48_profile_sensor) {
+               synaptics_profile_sensor_process(psmouse, &hw, num_fingers);
+               return;
+       }
+
        if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c))
                synaptics_report_semi_mt_data(dev, &hw, &priv->agm,
                                              num_fingers);
@@ -1360,6 +1404,9 @@ static void set_input_params(struct psmouse *psmouse,
        set_abs_position_params(dev, priv, ABS_X, ABS_Y);
        input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
 
+       if (cr48_profile_sensor)
+               input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0);
+
        if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) {
                set_abs_position_params(dev, priv, ABS_MT_POSITION_X,
                                        ABS_MT_POSITION_Y);
@@ -1371,11 +1418,16 @@ static void set_input_params(struct psmouse *psmouse,
                __set_bit(BTN_TOOL_QUADTAP, dev->keybit);
                __set_bit(BTN_TOOL_QUINTTAP, dev->keybit);
        } else if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) {
-               /* Non-image sensors with AGM use semi-mt */
-               __set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
-               input_mt_init_slots(dev, 2, 0);
                set_abs_position_params(dev, priv, ABS_MT_POSITION_X,
                                        ABS_MT_POSITION_Y);
+               /*
+                * Profile sensor in CR-48 tracks contacts reasonably well,
+                * other non-image sensors with AGM use semi-mt.
+                */
+               input_mt_init_slots(dev, 2,
+                                   INPUT_MT_POINTER |
+                                   (cr48_profile_sensor ?
+                                       INPUT_MT_TRACK : INPUT_MT_SEMI_MT));
        }
 
        if (SYN_CAP_PALMDETECT(priv->capabilities))
@@ -1577,10 +1629,24 @@ static const struct dmi_system_id olpc_dmi_table[] __initconst = {
        { }
 };
 
+static const struct dmi_system_id __initconst cr48_dmi_table[] = {
+#if defined(CONFIG_DMI) && defined(CONFIG_X86)
+       {
+               /* Cr-48 Chromebook (Codename Mario) */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "IEC"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Mario"),
+               },
+       },
+#endif
+       { }
+};
+
 void __init synaptics_module_init(void)
 {
        impaired_toshiba_kbc = dmi_check_system(toshiba_dmi_table);
        broken_olpc_ec = dmi_check_system(olpc_dmi_table);
+       cr48_profile_sensor = dmi_check_system(cr48_dmi_table);
 }
 
 static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode)
index d6aa4c67dbb6208e0584c098864a52e580950cff..93cb7912703cee4a9dbd2f75594a16da2937bcef 100644 (file)
@@ -17,7 +17,6 @@ static int i8042_aux_irq = -1;
 #define I8042_MUX_PHYS_DESC "sparcps2/serio%d"
 
 static void __iomem *kbd_iobase;
-static struct resource *kbd_res;
 
 #define I8042_COMMAND_REG      (kbd_iobase + 0x64UL)
 #define I8042_DATA_REG         (kbd_iobase + 0x60UL)
@@ -44,6 +43,8 @@ static inline void i8042_write_command(int val)
 
 #ifdef CONFIG_PCI
 
+static struct resource *kbd_res;
+
 #define OBP_PS2KBD_NAME1       "kb_ps2"
 #define OBP_PS2KBD_NAME2       "keyboard"
 #define OBP_PS2MS_NAME1                "kdmouse"
index 03b85711cb70c9406aae09647d12df68045ff2b3..db178ed2b47ee282c27a5f424f45df168b99a091 100644 (file)
@@ -359,7 +359,6 @@ static int mxt_bootloader_read(struct mxt_data *data,
        msg.buf = val;
 
        ret = i2c_transfer(data->client->adapter, &msg, 1);
-
        if (ret == 1) {
                ret = 0;
        } else {
@@ -414,6 +413,7 @@ static int mxt_lookup_bootloader_address(struct mxt_data *data, bool retry)
        case 0x5b:
                bootloader = appmode - 0x26;
                break;
+
        default:
                dev_err(&data->client->dev,
                        "Appmode i2c address 0x%02x not found\n",
@@ -425,20 +425,20 @@ static int mxt_lookup_bootloader_address(struct mxt_data *data, bool retry)
        return 0;
 }
 
-static int mxt_probe_bootloader(struct mxt_data *data, bool retry)
+static int mxt_probe_bootloader(struct mxt_data *data, bool alt_address)
 {
        struct device *dev = &data->client->dev;
-       int ret;
+       int error;
        u8 val;
        bool crc_failure;
 
-       ret = mxt_lookup_bootloader_address(data, retry);
-       if (ret)
-               return ret;
+       error = mxt_lookup_bootloader_address(data, alt_address);
+       if (error)
+               return error;
 
-       ret = mxt_bootloader_read(data, &val, 1);
-       if (ret)
-               return ret;
+       error = mxt_bootloader_read(data, &val, 1);
+       if (error)
+               return error;
 
        /* Check app crc fail mode */
        crc_failure = (val & ~MXT_BOOT_STATUS_MASK) == MXT_APP_CRC_FAIL;
@@ -1064,6 +1064,137 @@ static u32 mxt_calculate_crc(u8 *base, off_t start_off, off_t end_off)
        return crc;
 }
 
+static int mxt_prepare_cfg_mem(struct mxt_data *data,
+                              const struct firmware *cfg,
+                              unsigned int data_pos,
+                              unsigned int cfg_start_ofs,
+                              u8 *config_mem,
+                              size_t config_mem_size)
+{
+       struct device *dev = &data->client->dev;
+       struct mxt_object *object;
+       unsigned int type, instance, size, byte_offset;
+       int offset;
+       int ret;
+       int i;
+       u16 reg;
+       u8 val;
+
+       while (data_pos < cfg->size) {
+               /* Read type, instance, length */
+               ret = sscanf(cfg->data + data_pos, "%x %x %x%n",
+                            &type, &instance, &size, &offset);
+               if (ret == 0) {
+                       /* EOF */
+                       break;
+               } else if (ret != 3) {
+                       dev_err(dev, "Bad format: failed to parse object\n");
+                       return -EINVAL;
+               }
+               data_pos += offset;
+
+               object = mxt_get_object(data, type);
+               if (!object) {
+                       /* Skip object */
+                       for (i = 0; i < size; i++) {
+                               ret = sscanf(cfg->data + data_pos, "%hhx%n",
+                                            &val, &offset);
+                               if (ret != 1) {
+                                       dev_err(dev, "Bad format in T%d at %d\n",
+                                               type, i);
+                                       return -EINVAL;
+                               }
+                               data_pos += offset;
+                       }
+                       continue;
+               }
+
+               if (size > mxt_obj_size(object)) {
+                       /*
+                        * Either we are in fallback mode due to wrong
+                        * config or config from a later fw version,
+                        * or the file is corrupt or hand-edited.
+                        */
+                       dev_warn(dev, "Discarding %zu byte(s) in T%u\n",
+                                size - mxt_obj_size(object), type);
+               } else if (mxt_obj_size(object) > size) {
+                       /*
+                        * If firmware is upgraded, new bytes may be added to
+                        * end of objects. It is generally forward compatible
+                        * to zero these bytes - previous behaviour will be
+                        * retained. However this does invalidate the CRC and
+                        * will force fallback mode until the configuration is
+                        * updated. We warn here but do nothing else - the
+                        * malloc has zeroed the entire configuration.
+                        */
+                       dev_warn(dev, "Zeroing %zu byte(s) in T%d\n",
+                                mxt_obj_size(object) - size, type);
+               }
+
+               if (instance >= mxt_obj_instances(object)) {
+                       dev_err(dev, "Object instances exceeded!\n");
+                       return -EINVAL;
+               }
+
+               reg = object->start_address + mxt_obj_size(object) * instance;
+
+               for (i = 0; i < size; i++) {
+                       ret = sscanf(cfg->data + data_pos, "%hhx%n",
+                                    &val,
+                                    &offset);
+                       if (ret != 1) {
+                               dev_err(dev, "Bad format in T%d at %d\n",
+                                       type, i);
+                               return -EINVAL;
+                       }
+                       data_pos += offset;
+
+                       if (i > mxt_obj_size(object))
+                               continue;
+
+                       byte_offset = reg + i - cfg_start_ofs;
+
+                       if (byte_offset >= 0 && byte_offset < config_mem_size) {
+                               *(config_mem + byte_offset) = val;
+                       } else {
+                               dev_err(dev, "Bad object: reg:%d, T%d, ofs=%d\n",
+                                       reg, object->type, byte_offset);
+                               return -EINVAL;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int mxt_upload_cfg_mem(struct mxt_data *data, unsigned int cfg_start,
+                             u8 *config_mem, size_t config_mem_size)
+{
+       unsigned int byte_offset = 0;
+       int error;
+
+       /* Write configuration as blocks */
+       while (byte_offset < config_mem_size) {
+               unsigned int size = config_mem_size - byte_offset;
+
+               if (size > MXT_MAX_BLOCK_WRITE)
+                       size = MXT_MAX_BLOCK_WRITE;
+
+               error = __mxt_write_reg(data->client,
+                                       cfg_start + byte_offset,
+                                       size, config_mem + byte_offset);
+               if (error) {
+                       dev_err(&data->client->dev,
+                               "Config write error, ret=%d\n", error);
+                       return error;
+               }
+
+               byte_offset += size;
+       }
+
+       return 0;
+}
+
 /*
  * mxt_update_cfg - download configuration to chip
  *
@@ -1087,26 +1218,20 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg)
 {
        struct device *dev = &data->client->dev;
        struct mxt_info cfg_info;
-       struct mxt_object *object;
        int ret;
        int offset;
        int data_pos;
-       int byte_offset;
        int i;
        int cfg_start_ofs;
        u32 info_crc, config_crc, calculated_crc;
        u8 *config_mem;
        size_t config_mem_size;
-       unsigned int type, instance, size;
-       u8 val;
-       u16 reg;
 
        mxt_update_crc(data, MXT_COMMAND_REPORTALL, 1);
 
        if (strncmp(cfg->data, MXT_CFG_MAGIC, strlen(MXT_CFG_MAGIC))) {
                dev_err(dev, "Unrecognised config file\n");
-               ret = -EINVAL;
-               goto release;
+               return -EINVAL;
        }
 
        data_pos = strlen(MXT_CFG_MAGIC);
@@ -1118,8 +1243,7 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg)
                             &offset);
                if (ret != 1) {
                        dev_err(dev, "Bad format\n");
-                       ret = -EINVAL;
-                       goto release;
+                       return -EINVAL;
                }
 
                data_pos += offset;
@@ -1127,30 +1251,26 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg)
 
        if (cfg_info.family_id != data->info.family_id) {
                dev_err(dev, "Family ID mismatch!\n");
-               ret = -EINVAL;
-               goto release;
+               return -EINVAL;
        }
 
        if (cfg_info.variant_id != data->info.variant_id) {
                dev_err(dev, "Variant ID mismatch!\n");
-               ret = -EINVAL;
-               goto release;
+               return -EINVAL;
        }
 
        /* Read CRCs */
        ret = sscanf(cfg->data + data_pos, "%x%n", &info_crc, &offset);
        if (ret != 1) {
                dev_err(dev, "Bad format: failed to parse Info CRC\n");
-               ret = -EINVAL;
-               goto release;
+               return -EINVAL;
        }
        data_pos += offset;
 
        ret = sscanf(cfg->data + data_pos, "%x%n", &config_crc, &offset);
        if (ret != 1) {
                dev_err(dev, "Bad format: failed to parse Config CRC\n");
-               ret = -EINVAL;
-               goto release;
+               return -EINVAL;
        }
        data_pos += offset;
 
@@ -1166,8 +1286,7 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg)
                } else if (config_crc == data->config_crc) {
                        dev_dbg(dev, "Config CRC 0x%06X: OK\n",
                                 data->config_crc);
-                       ret = 0;
-                       goto release;
+                       return 0;
                } else {
                        dev_info(dev, "Config CRC 0x%06X: does not match file 0x%06X\n",
                                 data->config_crc, config_crc);
@@ -1186,93 +1305,13 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg)
        config_mem = kzalloc(config_mem_size, GFP_KERNEL);
        if (!config_mem) {
                dev_err(dev, "Failed to allocate memory\n");
-               ret = -ENOMEM;
-               goto release;
+               return -ENOMEM;
        }
 
-       while (data_pos < cfg->size) {
-               /* Read type, instance, length */
-               ret = sscanf(cfg->data + data_pos, "%x %x %x%n",
-                            &type, &instance, &size, &offset);
-               if (ret == 0) {
-                       /* EOF */
-                       break;
-               } else if (ret != 3) {
-                       dev_err(dev, "Bad format: failed to parse object\n");
-                       ret = -EINVAL;
-                       goto release_mem;
-               }
-               data_pos += offset;
-
-               object = mxt_get_object(data, type);
-               if (!object) {
-                       /* Skip object */
-                       for (i = 0; i < size; i++) {
-                               ret = sscanf(cfg->data + data_pos, "%hhx%n",
-                                            &val,
-                                            &offset);
-                               data_pos += offset;
-                       }
-                       continue;
-               }
-
-               if (size > mxt_obj_size(object)) {
-                       /*
-                        * Either we are in fallback mode due to wrong
-                        * config or config from a later fw version,
-                        * or the file is corrupt or hand-edited.
-                        */
-                       dev_warn(dev, "Discarding %zu byte(s) in T%u\n",
-                                size - mxt_obj_size(object), type);
-               } else if (mxt_obj_size(object) > size) {
-                       /*
-                        * If firmware is upgraded, new bytes may be added to
-                        * end of objects. It is generally forward compatible
-                        * to zero these bytes - previous behaviour will be
-                        * retained. However this does invalidate the CRC and
-                        * will force fallback mode until the configuration is
-                        * updated. We warn here but do nothing else - the
-                        * malloc has zeroed the entire configuration.
-                        */
-                       dev_warn(dev, "Zeroing %zu byte(s) in T%d\n",
-                                mxt_obj_size(object) - size, type);
-               }
-
-               if (instance >= mxt_obj_instances(object)) {
-                       dev_err(dev, "Object instances exceeded!\n");
-                       ret = -EINVAL;
-                       goto release_mem;
-               }
-
-               reg = object->start_address + mxt_obj_size(object) * instance;
-
-               for (i = 0; i < size; i++) {
-                       ret = sscanf(cfg->data + data_pos, "%hhx%n",
-                                    &val,
-                                    &offset);
-                       if (ret != 1) {
-                               dev_err(dev, "Bad format in T%d\n", type);
-                               ret = -EINVAL;
-                               goto release_mem;
-                       }
-                       data_pos += offset;
-
-                       if (i > mxt_obj_size(object))
-                               continue;
-
-                       byte_offset = reg + i - cfg_start_ofs;
-
-                       if ((byte_offset >= 0)
-                           && (byte_offset <= config_mem_size)) {
-                               *(config_mem + byte_offset) = val;
-                       } else {
-                               dev_err(dev, "Bad object: reg:%d, T%d, ofs=%d\n",
-                                       reg, object->type, byte_offset);
-                               ret = -EINVAL;
-                               goto release_mem;
-                       }
-               }
-       }
+       ret = mxt_prepare_cfg_mem(data, cfg, data_pos, cfg_start_ofs,
+                                 config_mem, config_mem_size);
+       if (ret)
+               goto release_mem;
 
        /* Calculate crc of the received configs (not the raw config file) */
        if (data->T7_address < cfg_start_ofs) {
@@ -1286,28 +1325,14 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg)
                                           data->T7_address - cfg_start_ofs,
                                           config_mem_size);
 
-       if (config_crc > 0 && (config_crc != calculated_crc))
+       if (config_crc > 0 && config_crc != calculated_crc)
                dev_warn(dev, "Config CRC error, calculated=%06X, file=%06X\n",
                         calculated_crc, config_crc);
 
-       /* Write configuration as blocks */
-       byte_offset = 0;
-       while (byte_offset < config_mem_size) {
-               size = config_mem_size - byte_offset;
-
-               if (size > MXT_MAX_BLOCK_WRITE)
-                       size = MXT_MAX_BLOCK_WRITE;
-
-               ret = __mxt_write_reg(data->client,
-                                     cfg_start_ofs + byte_offset,
-                                     size, config_mem + byte_offset);
-               if (ret != 0) {
-                       dev_err(dev, "Config write error, ret=%d\n", ret);
-                       goto release_mem;
-               }
-
-               byte_offset += size;
-       }
+       ret = mxt_upload_cfg_mem(data, cfg_start_ofs,
+                                config_mem, config_mem_size);
+       if (ret)
+               goto release_mem;
 
        mxt_update_crc(data, MXT_COMMAND_BACKUPNV, MXT_BACKUP_VALUE);
 
@@ -1319,8 +1344,6 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg)
 
 release_mem:
        kfree(config_mem);
-release:
-       release_firmware(cfg);
        return ret;
 }
 
@@ -1422,10 +1445,12 @@ static int mxt_get_object_table(struct mxt_data *data)
 
                switch (object->type) {
                case MXT_GEN_MESSAGE_T5:
-                       if (data->info.family_id == 0x80) {
+                       if (data->info.family_id == 0x80 &&
+                           data->info.version < 0x20) {
                                /*
-                                * On mXT224 read and discard unused CRC byte
-                                * otherwise DMA reads are misaligned
+                                * On mXT224 firmware versions prior to V2.0
+                                * read and discard unused CRC byte otherwise
+                                * DMA reads are misaligned.
                                 */
                                data->T5_msg_size = mxt_obj_size(object);
                        } else {
@@ -1433,6 +1458,7 @@ static int mxt_get_object_table(struct mxt_data *data)
                                data->T5_msg_size = mxt_obj_size(object) - 1;
                        }
                        data->T5_address = object->start_address;
+                       break;
                case MXT_GEN_COMMAND_T6:
                        data->T6_reportid = min_id;
                        data->T6_address = object->start_address;
@@ -1638,46 +1664,45 @@ static int mxt_configure_objects(struct mxt_data *data,
 static void mxt_config_cb(const struct firmware *cfg, void *ctx)
 {
        mxt_configure_objects(ctx, cfg);
+       release_firmware(cfg);
 }
 
 static int mxt_initialize(struct mxt_data *data)
 {
        struct i2c_client *client = data->client;
+       int recovery_attempts = 0;
        int error;
-       bool alt_bootloader_addr = false;
-       bool retry = false;
 
-retry_info:
-       error = mxt_get_info(data);
-       if (error) {
-retry_bootloader:
-               error = mxt_probe_bootloader(data, alt_bootloader_addr);
+       while (1) {
+               error = mxt_get_info(data);
+               if (!error)
+                       break;
+
+               /* Check bootloader state */
+               error = mxt_probe_bootloader(data, false);
                if (error) {
-                       if (alt_bootloader_addr) {
+                       dev_info(&client->dev, "Trying alternate bootloader address\n");
+                       error = mxt_probe_bootloader(data, true);
+                       if (error) {
                                /* Chip is not in appmode or bootloader mode */
                                return error;
                        }
+               }
 
-                       dev_info(&client->dev, "Trying alternate bootloader address\n");
-                       alt_bootloader_addr = true;
-                       goto retry_bootloader;
-               } else {
-                       if (retry) {
-                               dev_err(&client->dev, "Could not recover from bootloader mode\n");
-                               /*
-                                * We can reflash from this state, so do not
-                                * abort init
-                                */
-                               data->in_bootloader = true;
-                               return 0;
-                       }
-
-                       /* Attempt to exit bootloader into app mode */
-                       mxt_send_bootloader_cmd(data, false);
-                       msleep(MXT_FW_RESET_TIME);
-                       retry = true;
-                       goto retry_info;
+               /* OK, we are in bootloader, see if we can recover */
+               if (++recovery_attempts > 1) {
+                       dev_err(&client->dev, "Could not recover from bootloader mode\n");
+                       /*
+                        * We can reflash from this state, so do not
+                        * abort initialization.
+                        */
+                       data->in_bootloader = true;
+                       return 0;
                }
+
+               /* Attempt to exit bootloader into app mode */
+               mxt_send_bootloader_cmd(data, false);
+               msleep(MXT_FW_RESET_TIME);
        }
 
        /* Get object table information */
@@ -1687,13 +1712,18 @@ retry_bootloader:
                return error;
        }
 
-       mxt_acquire_irq(data);
+       error = mxt_acquire_irq(data);
        if (error)
                goto err_free_object_table;
 
-       request_firmware_nowait(THIS_MODULE, true, MXT_CFG_NAME,
-                               &data->client->dev, GFP_KERNEL, data,
-                               mxt_config_cb);
+       error = request_firmware_nowait(THIS_MODULE, true, MXT_CFG_NAME,
+                                       &client->dev, GFP_KERNEL, data,
+                                       mxt_config_cb);
+       if (error) {
+               dev_err(&client->dev, "Failed to invoke firmware loader: %d\n",
+                       error);
+               goto err_free_object_table;
+       }
 
        return 0;
 
index 5a6d50c004d73c9b2d6ceb2a4b573e1542b11b7f..8857d5b9be71dc03d4494562383fc76c779003ef 100644 (file)
@@ -262,7 +262,6 @@ static int edt_ft5x06_register_write(struct edt_ft5x06_ts_data *tsdata,
        case M06:
                wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc;
                wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
-               wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
                wrbuf[2] = value;
                wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2];
                return edt_ft5x06_ts_readwrite(tsdata->client, 4,
index 18405314168be35fb00640bbf1e7e05ba23a9466..ecb0109a536045019dc3c5b9e2c084c3628f16ce 100644 (file)
@@ -3149,14 +3149,16 @@ free_domains:
 
 static void cleanup_domain(struct protection_domain *domain)
 {
-       struct iommu_dev_data *dev_data, *next;
+       struct iommu_dev_data *entry;
        unsigned long flags;
 
        write_lock_irqsave(&amd_iommu_devtable_lock, flags);
 
-       list_for_each_entry_safe(dev_data, next, &domain->dev_list, list) {
-               __detach_device(dev_data);
-               atomic_set(&dev_data->bind, 0);
+       while (!list_empty(&domain->dev_list)) {
+               entry = list_first_entry(&domain->dev_list,
+                                        struct iommu_dev_data, list);
+               __detach_device(entry);
+               atomic_set(&entry->bind, 0);
        }
 
        write_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
index d1f5caad04f99a8ed2e3781d5bcedce7c324564e..5619f264862d9073a587fd1a2b919f2c61a27523 100644 (file)
@@ -3869,6 +3869,14 @@ static int device_notifier(struct notifier_block *nb,
            action != BUS_NOTIFY_DEL_DEVICE)
                return 0;
 
+       /*
+        * If the device is still attached to a device driver we can't
+        * tear down the domain yet as DMA mappings may still be in use.
+        * Wait for the BUS_NOTIFY_UNBOUND_DRIVER event to do that.
+        */
+       if (action == BUS_NOTIFY_DEL_DEVICE && dev->driver != NULL)
+               return 0;
+
        domain = find_domain(dev);
        if (!domain)
                return 0;
index 169836020208d1a8a5755f16b60f68a66fec6d43..ac4adb337038bc990077a2c0557d1f07d8b1de8e 100644 (file)
@@ -995,7 +995,7 @@ int iommu_map(struct iommu_domain *domain, unsigned long iova,
        size_t orig_size = size;
        int ret = 0;
 
-       if (unlikely(domain->ops->unmap == NULL ||
+       if (unlikely(domain->ops->map == NULL ||
                     domain->ops->pgsize_bitmap == 0UL))
                return -ENODEV;
 
index b7ae0a0dd5b6814c61332d3f56b4b7626754ddea..aecec6d3246370004a0e9434a1f58303e96b7c46 100644 (file)
@@ -2365,7 +2365,7 @@ static int gigaset_probe(struct usb_interface *interface,
        endpoint = &hostif->endpoint[0].desc;
        usb_fill_int_urb(ucs->urb_int_in, udev,
                         usb_rcvintpipe(udev,
-                                       (endpoint->bEndpointAddress) & 0x0f),
+                                       usb_endpoint_num(endpoint)),
                         ucs->int_in_buf, IP_MSGSIZE, read_int_callback, cs,
                         endpoint->bInterval);
        rc = usb_submit_urb(ucs->urb_int_in, GFP_KERNEL);
index d0a41cb0cf627fe8c6687324e93f9dd3cb0384b7..00d40773b07fa073840feecf89f5a3cf2428e4ee 100644 (file)
@@ -751,7 +751,7 @@ static int gigaset_probe(struct usb_interface *interface,
        /* Fill the interrupt urb and send it to the core */
        usb_fill_int_urb(ucs->read_urb, udev,
                         usb_rcvintpipe(udev,
-                                       endpoint->bEndpointAddress & 0x0f),
+                                       usb_endpoint_num(endpoint)),
                         ucs->rcvbuf, buffer_size,
                         gigaset_read_int_callback,
                         cs, endpoint->bInterval);
index 58368f7b5cba150e736c24d7c5f151347c7f43d8..2498c349a32e49e9379559224b2652d6e9d33e82 100644 (file)
@@ -1,6 +1,6 @@
 /* $Id: xdi_msg.h,v 1.1.2.2 2001/02/16 08:40:36 armin Exp $ */
 
-#ifndef __DIVA_XDI_UM_CFG_MESSSGE_H__
+#ifndef __DIVA_XDI_UM_CFG_MESSAGE_H__
 #define __DIVA_XDI_UM_CFG_MESSAGE_H__
 
 /*
index a4f05c54c32b021cc04fb9ea65ece506a1e94e2a..87f7dff20ff66b269537b166642690722fd4accc 100644 (file)
@@ -1454,66 +1454,63 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members)
 #ifdef CMX_CONF_DEBUG
        if (0) {
 #else
-               if (members == 2) {
+       if (members == 2) {
 #endif
-                       /* "other" becomes other party */
-                       other = (list_entry(conf->mlist.next,
-                                           struct dsp_conf_member, list))->dsp;
-                       if (other == member)
-                               other = (list_entry(conf->mlist.prev,
-                                                   struct dsp_conf_member, list))->dsp;
-                       o_q = other->rx_buff; /* received data */
-                       o_rr = (other->rx_R + len) & CMX_BUFF_MASK;
-                       /* end of rx-pointer */
-                       o_r = (o_rr - rr + r) & CMX_BUFF_MASK;
-                       /* start rx-pointer at current read position*/
-                       /* -> if echo is NOT enabled */
-                       if (!dsp->echo.software) {
-                               /*
-                                * -> copy other member's rx-data,
-                                * if tx-data is available, mix
-                                */
-                               while (o_r != o_rr && t != tt) {
-                                       *d++ = dsp_audio_mix_law[(p[t] << 8) | o_q[o_r]];
-                                       t = (t + 1) & CMX_BUFF_MASK;
-                                       o_r = (o_r + 1) & CMX_BUFF_MASK;
-                               }
-                               while (o_r != o_rr) {
-                                       *d++ = o_q[o_r];
-                                       o_r = (o_r + 1) & CMX_BUFF_MASK;
-                               }
-                               /* -> if echo is enabled */
-                       } else {
-                               /*
-                                * -> mix other member's rx-data with echo,
-                                * if tx-data is available, mix
-                                */
-                               while (r != rr && t != tt) {
-                                       sample = dsp_audio_law_to_s32[p[t]] +
-                                               dsp_audio_law_to_s32[q[r]] +
-                                               dsp_audio_law_to_s32[o_q[o_r]];
-                                       if (sample < -32768)
-                                               sample = -32768;
-                                       else if (sample > 32767)
-                                               sample = 32767;
-                                       *d++ = dsp_audio_s16_to_law[sample & 0xffff];
-                                       /* tx-data + rx_data + echo */
-                                       t = (t + 1) & CMX_BUFF_MASK;
-                                       r = (r + 1) & CMX_BUFF_MASK;
-                                       o_r = (o_r + 1) & CMX_BUFF_MASK;
-                               }
-                               while (r != rr) {
-                                       *d++ = dsp_audio_mix_law[(q[r] << 8) | o_q[o_r]];
-                                       r = (r + 1) & CMX_BUFF_MASK;
-                                       o_r = (o_r + 1) & CMX_BUFF_MASK;
-                               }
+               /* "other" becomes other party */
+               other = (list_entry(conf->mlist.next,
+                                   struct dsp_conf_member, list))->dsp;
+               if (other == member)
+                       other = (list_entry(conf->mlist.prev,
+                                   struct dsp_conf_member, list))->dsp;
+               o_q = other->rx_buff; /* received data */
+               o_rr = (other->rx_R + len) & CMX_BUFF_MASK;
+               /* end of rx-pointer */
+               o_r = (o_rr - rr + r) & CMX_BUFF_MASK;
+               /* start rx-pointer at current read position*/
+               /* -> if echo is NOT enabled */
+               if (!dsp->echo.software) {
+                       /*
+                        * -> copy other member's rx-data,
+                        * if tx-data is available, mix
+                        */
+                       while (o_r != o_rr && t != tt) {
+                               *d++ = dsp_audio_mix_law[(p[t] << 8) | o_q[o_r]];
+                               t = (t + 1) & CMX_BUFF_MASK;
+                               o_r = (o_r + 1) & CMX_BUFF_MASK;
+                       }
+                       while (o_r != o_rr) {
+                               *d++ = o_q[o_r];
+                               o_r = (o_r + 1) & CMX_BUFF_MASK;
+                       }
+                       /* -> if echo is enabled */
+               } else {
+                       /*
+                        * -> mix other member's rx-data with echo,
+                        * if tx-data is available, mix
+                        */
+                       while (r != rr && t != tt) {
+                               sample = dsp_audio_law_to_s32[p[t]] +
+                                       dsp_audio_law_to_s32[q[r]] +
+                                       dsp_audio_law_to_s32[o_q[o_r]];
+                               if (sample < -32768)
+                                       sample = -32768;
+                               else if (sample > 32767)
+                                       sample = 32767;
+                               *d++ = dsp_audio_s16_to_law[sample & 0xffff];
+                               /* tx-data + rx_data + echo */
+                               t = (t + 1) & CMX_BUFF_MASK;
+                               r = (r + 1) & CMX_BUFF_MASK;
+                               o_r = (o_r + 1) & CMX_BUFF_MASK;
+                       }
+                       while (r != rr) {
+                               *d++ = dsp_audio_mix_law[(q[r] << 8) | o_q[o_r]];
+                               r = (r + 1) & CMX_BUFF_MASK;
+                               o_r = (o_r + 1) & CMX_BUFF_MASK;
                        }
-                       dsp->tx_R = t;
-                       goto send_packet;
                }
-#ifdef DSP_NEVER_DEFINED
+               dsp->tx_R = t;
+               goto send_packet;
        }
-#endif
        /* PROCESS DATA (three or more members) */
        /* -> if echo is NOT enabled */
        if (!dsp->echo.software) {
index 129729d35478bf5934cb69c90a688a9c43399759..aa29198fca3e2b2c892268eb2549444b1beb499c 100644 (file)
 #include <linux/list.h>
 #include <linux/spinlock.h>
 #include <linux/device.h>
+#include <linux/timer.h>
 #include <linux/err.h>
 #include <linux/ctype.h>
 #include <linux/leds.h>
-#include <linux/workqueue.h>
 #include "leds.h"
 
 static struct class *leds_class;
@@ -97,10 +97,9 @@ static const struct attribute_group *led_groups[] = {
        NULL,
 };
 
-static void led_work_function(struct work_struct *ws)
+static void led_timer_function(unsigned long data)
 {
-       struct led_classdev *led_cdev =
-               container_of(ws, struct led_classdev, blink_work.work);
+       struct led_classdev *led_cdev = (void *)data;
        unsigned long brightness;
        unsigned long delay;
 
@@ -144,8 +143,7 @@ static void led_work_function(struct work_struct *ws)
                }
        }
 
-       queue_delayed_work(system_wq, &led_cdev->blink_work,
-                          msecs_to_jiffies(delay));
+       mod_timer(&led_cdev->blink_timer, jiffies + msecs_to_jiffies(delay));
 }
 
 static void set_brightness_delayed(struct work_struct *ws)
@@ -233,7 +231,9 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
 
        INIT_WORK(&led_cdev->set_brightness_work, set_brightness_delayed);
 
-       INIT_DELAYED_WORK(&led_cdev->blink_work, led_work_function);
+       init_timer(&led_cdev->blink_timer);
+       led_cdev->blink_timer.function = led_timer_function;
+       led_cdev->blink_timer.data = (unsigned long)led_cdev;
 
 #ifdef CONFIG_LEDS_TRIGGERS
        led_trigger_set_default(led_cdev);
index 4bb116867b88af7249c1576e614e8ad0685f7945..71b40d3bf77604e32829f391b6e804bbeefb0cf1 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/module.h>
 #include <linux/rwsem.h>
 #include <linux/leds.h>
-#include <linux/workqueue.h>
 #include "leds.h"
 
 DECLARE_RWSEM(leds_list_lock);
@@ -52,7 +51,7 @@ static void led_set_software_blink(struct led_classdev *led_cdev,
                return;
        }
 
-       queue_delayed_work(system_wq, &led_cdev->blink_work, 1);
+       mod_timer(&led_cdev->blink_timer, jiffies + 1);
 }
 
 
@@ -76,7 +75,7 @@ void led_blink_set(struct led_classdev *led_cdev,
                   unsigned long *delay_on,
                   unsigned long *delay_off)
 {
-       cancel_delayed_work_sync(&led_cdev->blink_work);
+       del_timer_sync(&led_cdev->blink_timer);
 
        led_cdev->flags &= ~LED_BLINK_ONESHOT;
        led_cdev->flags &= ~LED_BLINK_ONESHOT_STOP;
@@ -91,7 +90,7 @@ void led_blink_set_oneshot(struct led_classdev *led_cdev,
                           int invert)
 {
        if ((led_cdev->flags & LED_BLINK_ONESHOT) &&
-            delayed_work_pending(&led_cdev->blink_work))
+            timer_pending(&led_cdev->blink_timer))
                return;
 
        led_cdev->flags |= LED_BLINK_ONESHOT;
@@ -108,7 +107,7 @@ EXPORT_SYMBOL(led_blink_set_oneshot);
 
 void led_stop_software_blink(struct led_classdev *led_cdev)
 {
-       cancel_delayed_work_sync(&led_cdev->blink_work);
+       del_timer_sync(&led_cdev->blink_timer);
        led_cdev->blink_delay_on = 0;
        led_cdev->blink_delay_off = 0;
 }
@@ -117,7 +116,7 @@ EXPORT_SYMBOL_GPL(led_stop_software_blink);
 void led_set_brightness(struct led_classdev *led_cdev,
                        enum led_brightness brightness)
 {
-       /* delay brightness setting if need to stop soft-blink work */
+       /* delay brightness setting if need to stop soft-blink timer */
        if (led_cdev->blink_delay_on || led_cdev->blink_delay_off) {
                led_cdev->delayed_set_value = brightness;
                schedule_work(&led_cdev->set_brightness_work);
index 2785007e0e462597d3b8e74839a8bfe25aa90b9c..cd15e0801228437fb7945c300ca4ca206ffc8efe 100644 (file)
@@ -1688,6 +1688,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        unsigned int key_size, opt_params;
        unsigned long long tmpll;
        int ret;
+       size_t iv_size_padding;
        struct dm_arg_set as;
        const char *opt_string;
        char dummy;
@@ -1724,20 +1725,32 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 
        cc->dmreq_start = sizeof(struct ablkcipher_request);
        cc->dmreq_start += crypto_ablkcipher_reqsize(any_tfm(cc));
-       cc->dmreq_start = ALIGN(cc->dmreq_start, crypto_tfm_ctx_alignment());
-       cc->dmreq_start += crypto_ablkcipher_alignmask(any_tfm(cc)) &
-                          ~(crypto_tfm_ctx_alignment() - 1);
+       cc->dmreq_start = ALIGN(cc->dmreq_start, __alignof__(struct dm_crypt_request));
+
+       if (crypto_ablkcipher_alignmask(any_tfm(cc)) < CRYPTO_MINALIGN) {
+               /* Allocate the padding exactly */
+               iv_size_padding = -(cc->dmreq_start + sizeof(struct dm_crypt_request))
+                               & crypto_ablkcipher_alignmask(any_tfm(cc));
+       } else {
+               /*
+                * If the cipher requires greater alignment than kmalloc
+                * alignment, we don't know the exact position of the
+                * initialization vector. We must assume worst case.
+                */
+               iv_size_padding = crypto_ablkcipher_alignmask(any_tfm(cc));
+       }
 
        cc->req_pool = mempool_create_kmalloc_pool(MIN_IOS, cc->dmreq_start +
-                       sizeof(struct dm_crypt_request) + cc->iv_size);
+                       sizeof(struct dm_crypt_request) + iv_size_padding + cc->iv_size);
        if (!cc->req_pool) {
                ti->error = "Cannot allocate crypt request mempool";
                goto bad;
        }
 
        cc->per_bio_data_size = ti->per_bio_data_size =
-                               sizeof(struct dm_crypt_io) + cc->dmreq_start +
-                               sizeof(struct dm_crypt_request) + cc->iv_size;
+               ALIGN(sizeof(struct dm_crypt_io) + cc->dmreq_start +
+                     sizeof(struct dm_crypt_request) + iv_size_padding + cc->iv_size,
+                     ARCH_KMALLOC_MINALIGN);
 
        cc->page_pool = mempool_create_page_pool(MIN_POOL_PAGES, 0);
        if (!cc->page_pool) {
index b08c18871323c904f3964e9c8b650366ad2979ef..6703751d87d7fd7314149cfd8ba5bef314927235 100644 (file)
@@ -2953,6 +2953,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr,
                 */
                if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) {
                        end_reshape(conf);
+                       close_sync(conf);
                        return 0;
                }
 
@@ -3081,6 +3082,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr,
                        }
 
                        r10_bio = mempool_alloc(conf->r10buf_pool, GFP_NOIO);
+                       r10_bio->state = 0;
                        raise_barrier(conf, rb2 != NULL);
                        atomic_set(&r10_bio->remaining, 0);
 
@@ -3269,6 +3271,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr,
                if (sync_blocks < max_sync)
                        max_sync = sync_blocks;
                r10_bio = mempool_alloc(conf->r10buf_pool, GFP_NOIO);
+               r10_bio->state = 0;
 
                r10_bio->mddev = mddev;
                atomic_set(&r10_bio->remaining, 0);
@@ -4384,6 +4387,7 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr,
 read_more:
        /* Now schedule reads for blocks from sector_nr to last */
        r10_bio = mempool_alloc(conf->r10buf_pool, GFP_NOIO);
+       r10_bio->state = 0;
        raise_barrier(conf, sectors_done != 0);
        atomic_set(&r10_bio->remaining, 0);
        r10_bio->mddev = mddev;
@@ -4398,6 +4402,7 @@ read_more:
                 * on all the target devices.
                 */
                // FIXME
+               mempool_free(r10_bio, conf->r10buf_pool);
                set_bit(MD_RECOVERY_INTR, &mddev->recovery);
                return sectors_done;
        }
@@ -4410,7 +4415,7 @@ read_more:
        read_bio->bi_private = r10_bio;
        read_bio->bi_end_io = end_sync_read;
        read_bio->bi_rw = READ;
-       read_bio->bi_flags &= ~(BIO_POOL_MASK - 1);
+       read_bio->bi_flags &= (~0UL << BIO_RESET_BITS);
        read_bio->bi_flags |= 1 << BIO_UPTODATE;
        read_bio->bi_vcnt = 0;
        read_bio->bi_iter.bi_size = 0;
index 6234b2e84587cd75d37ac50bf5264094e474632a..183588b11fc1d261e173aff9c9e1e63b175ed120 100644 (file)
@@ -2922,7 +2922,7 @@ static int fetch_block(struct stripe_head *sh, struct stripe_head_state *s,
              (!test_bit(R5_Insync, &dev->flags) || test_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) &&
              !test_bit(R5_OVERWRITE, &fdev[0]->flags)) ||
             (sh->raid_conf->level == 6 && s->failed && s->to_write &&
-             s->to_write < sh->raid_conf->raid_disks - 2 &&
+             s->to_write - s->non_overwrite < sh->raid_conf->raid_disks - 2 &&
              (!test_bit(R5_Insync, &dev->flags) || test_bit(STRIPE_PREREAD_ACTIVE, &sh->state))))) {
                /* we would like to get this block, possibly by computing it,
                 * otherwise read it if the backing disk is insync
@@ -3817,6 +3817,8 @@ static void handle_stripe(struct stripe_head *sh)
                                set_bit(R5_Wantwrite, &dev->flags);
                                if (prexor)
                                        continue;
+                               if (s.failed > 1)
+                                       continue;
                                if (!test_bit(R5_Insync, &dev->flags) ||
                                    ((i == sh->pd_idx || i == sh->qd_idx)  &&
                                     s.failed == 0))
index ce48aa72bb429ef724eb4f15cb695e9c70d3a8e2..bde2fc0724103a26864476cb27e0718c3937e2a9 100644 (file)
@@ -1754,7 +1754,7 @@ static int ab8500_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
-#if CONFIG_DEBUG_FS
+#ifdef CONFIG_DEBUG_FS
        /* Pass to debugfs */
        ab8500_debug_resources[0].start = ab8500->irq;
        ab8500_debug_resources[0].end = ab8500->irq;
index b44f0203983bfb5117c02be8469074814c24a18f..6bdb78c2ac77de535214d80a09cd9a302653d219 100644 (file)
@@ -404,7 +404,7 @@ static int htcpld_register_chip_i2c(
        }
 
        i2c_set_clientdata(client, chip);
-       snprintf(client->name, I2C_NAME_SIZE, "Chip_0x%d", client->addr);
+       snprintf(client->name, I2C_NAME_SIZE, "Chip_0x%x", client->addr);
        chip->client = client;
 
        /* Reset the chip */
index 33a9234b701c51b7c30c899c026fc92f6d4a0771..83dab2f0a50e2a1f6d63fe3d340d38a85b4afe3b 100644 (file)
@@ -647,7 +647,7 @@ static int usbhs_omap_probe(struct platform_device *pdev)
                default:
                        omap->nports = OMAP3_HS_USB_PORTS;
                        dev_dbg(dev,
-                        "USB HOST Rev:0x%d not recognized, assuming %d ports\n",
+                        "USB HOST Rev:0x%x not recognized, assuming %d ports\n",
                         omap->usbhs_rev, omap->nports);
                        break;
                }
index 3bc969a5916b8249c193a44e71eb89c4c077be85..4d3ff37714916451903f39aa30d47ab46e0f4d62 100644 (file)
@@ -724,24 +724,24 @@ static struct twl4030_script *omap3_idle_scripts[] = {
  * above.
  */
 static struct twl4030_resconfig omap3_idle_rconfig[] = {
-       TWL_REMAP_SLEEP(RES_VAUX1, DEV_GRP_NULL, 0, 0),
-       TWL_REMAP_SLEEP(RES_VAUX2, DEV_GRP_NULL, 0, 0),
-       TWL_REMAP_SLEEP(RES_VAUX3, DEV_GRP_NULL, 0, 0),
-       TWL_REMAP_SLEEP(RES_VAUX4, DEV_GRP_NULL, 0, 0),
-       TWL_REMAP_SLEEP(RES_VMMC1, DEV_GRP_NULL, 0, 0),
-       TWL_REMAP_SLEEP(RES_VMMC2, DEV_GRP_NULL, 0, 0),
+       TWL_REMAP_SLEEP(RES_VAUX1, TWL4030_RESCONFIG_UNDEF, 0, 0),
+       TWL_REMAP_SLEEP(RES_VAUX2, TWL4030_RESCONFIG_UNDEF, 0, 0),
+       TWL_REMAP_SLEEP(RES_VAUX3, TWL4030_RESCONFIG_UNDEF, 0, 0),
+       TWL_REMAP_SLEEP(RES_VAUX4, TWL4030_RESCONFIG_UNDEF, 0, 0),
+       TWL_REMAP_SLEEP(RES_VMMC1, TWL4030_RESCONFIG_UNDEF, 0, 0),
+       TWL_REMAP_SLEEP(RES_VMMC2, TWL4030_RESCONFIG_UNDEF, 0, 0),
        TWL_REMAP_OFF(RES_VPLL1, DEV_GRP_P1, 3, 1),
        TWL_REMAP_SLEEP(RES_VPLL2, DEV_GRP_P1, 0, 0),
-       TWL_REMAP_SLEEP(RES_VSIM, DEV_GRP_NULL, 0, 0),
-       TWL_REMAP_SLEEP(RES_VDAC, DEV_GRP_NULL, 0, 0),
+       TWL_REMAP_SLEEP(RES_VSIM, TWL4030_RESCONFIG_UNDEF, 0, 0),
+       TWL_REMAP_SLEEP(RES_VDAC, TWL4030_RESCONFIG_UNDEF, 0, 0),
        TWL_REMAP_SLEEP(RES_VINTANA1, TWL_DEV_GRP_P123, 1, 2),
        TWL_REMAP_SLEEP(RES_VINTANA2, TWL_DEV_GRP_P123, 0, 2),
        TWL_REMAP_SLEEP(RES_VINTDIG, TWL_DEV_GRP_P123, 1, 2),
        TWL_REMAP_SLEEP(RES_VIO, TWL_DEV_GRP_P123, 2, 2),
        TWL_REMAP_OFF(RES_VDD1, DEV_GRP_P1, 4, 1),
        TWL_REMAP_OFF(RES_VDD2, DEV_GRP_P1, 3, 1),
-       TWL_REMAP_SLEEP(RES_VUSB_1V5, DEV_GRP_NULL, 0, 0),
-       TWL_REMAP_SLEEP(RES_VUSB_1V8, DEV_GRP_NULL, 0, 0),
+       TWL_REMAP_SLEEP(RES_VUSB_1V5, TWL4030_RESCONFIG_UNDEF, 0, 0),
+       TWL_REMAP_SLEEP(RES_VUSB_1V8, TWL4030_RESCONFIG_UNDEF, 0, 0),
        TWL_REMAP_SLEEP(RES_VUSB_3V1, TWL_DEV_GRP_P123, 0, 0),
        /* Resource #20 USB charge pump skipped */
        TWL_REMAP_SLEEP(RES_REGEN, TWL_DEV_GRP_P123, 2, 1),
index 324e1de936871952c726d42a33826c19a827cdb8..2da05c0e113d0b62d917e4de4b12e15b46defac8 100644 (file)
@@ -601,6 +601,7 @@ int mei_cl_connect(struct mei_cl *cl, struct file *file)
                cl->timer_count = MEI_CONNECT_TIMEOUT;
                list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
        } else {
+               cl->state = MEI_FILE_INITIALIZING;
                list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
        }
 
index 3095fc514a65f3a44868587e6adae91b0eef5612..5ccc23bc76904a3b1dbe2770667e7aad502f96cf 100644 (file)
@@ -342,9 +342,10 @@ static int mei_nfc_send(struct mei_cl_device *cldev, u8 *buf, size_t length)
        ndev = (struct mei_nfc_dev *) cldev->priv_data;
        dev = ndev->cl->dev;
 
+       err = -ENOMEM;
        mei_buf = kzalloc(length + MEI_NFC_HEADER_SIZE, GFP_KERNEL);
        if (!mei_buf)
-               return -ENOMEM;
+               goto out;
 
        hdr = (struct mei_nfc_hci_hdr *) mei_buf;
        hdr->cmd = MEI_NFC_CMD_HCI_SEND;
@@ -354,12 +355,9 @@ static int mei_nfc_send(struct mei_cl_device *cldev, u8 *buf, size_t length)
        hdr->data_size = length;
 
        memcpy(mei_buf + MEI_NFC_HEADER_SIZE, buf, length);
-
        err = __mei_cl_send(ndev->cl, mei_buf, length + MEI_NFC_HEADER_SIZE);
        if (err < 0)
-               return err;
-
-       kfree(mei_buf);
+               goto out;
 
        if (!wait_event_interruptible_timeout(ndev->send_wq,
                                ndev->recv_req_id == ndev->req_id, HZ)) {
@@ -368,7 +366,8 @@ static int mei_nfc_send(struct mei_cl_device *cldev, u8 *buf, size_t length)
        } else {
                ndev->req_id++;
        }
-
+out:
+       kfree(mei_buf);
        return err;
 }
 
index 5a4bfe33112aba9307bdeac6877a4404b24bc7e7..46c4643b7a0776986890bef600674ec3823d01f0 100644 (file)
@@ -1434,6 +1434,10 @@ static int cfi_amdstd_otp_walk(struct mtd_info *mtd, loff_t from, size_t len,
 
                                mutex_lock(&chip->mutex);
                                ret = get_chip(map, chip, base, FL_LOCKING);
+                               if (ret) {
+                                       mutex_unlock(&chip->mutex);
+                                       return ret;
+                               }
 
                                /* Enter lock register command */
                                cfi_send_gen_cmd(0xAA, cfi->addr_unlock1,
index f0ed92e210a1fc39d1944e8240d0f4728d91835b..5967b385141b7f49bc669beda18ac69fbd7e06d0 100644 (file)
@@ -931,7 +931,7 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
        u32 val;
 
        val = readl(info->reg.gpmc_ecc_config);
-       if (((val >> ECC_CONFIG_CS_SHIFT)  & ~CS_MASK) != info->gpmc_cs)
+       if (((val >> ECC_CONFIG_CS_SHIFT) CS_MASK) != info->gpmc_cs)
                return -EINVAL;
 
        /* read ecc result */
@@ -1794,9 +1794,12 @@ static int omap_nand_probe(struct platform_device *pdev)
        }
 
        /* populate MTD interface based on ECC scheme */
-       nand_chip->ecc.layout   = &omap_oobinfo;
        ecclayout               = &omap_oobinfo;
        switch (info->ecc_opt) {
+       case OMAP_ECC_HAM1_CODE_SW:
+               nand_chip->ecc.mode = NAND_ECC_SOFT;
+               break;
+
        case OMAP_ECC_HAM1_CODE_HW:
                pr_info("nand: using OMAP_ECC_HAM1_CODE_HW\n");
                nand_chip->ecc.mode             = NAND_ECC_HW;
@@ -1848,7 +1851,7 @@ static int omap_nand_probe(struct platform_device *pdev)
                nand_chip->ecc.priv             = nand_bch_init(mtd,
                                                        nand_chip->ecc.size,
                                                        nand_chip->ecc.bytes,
-                                                       &nand_chip->ecc.layout);
+                                                       &ecclayout);
                if (!nand_chip->ecc.priv) {
                        pr_err("nand: error: unable to use s/w BCH library\n");
                        err = -EINVAL;
@@ -1923,7 +1926,7 @@ static int omap_nand_probe(struct platform_device *pdev)
                nand_chip->ecc.priv             = nand_bch_init(mtd,
                                                        nand_chip->ecc.size,
                                                        nand_chip->ecc.bytes,
-                                                       &nand_chip->ecc.layout);
+                                                       &ecclayout);
                if (!nand_chip->ecc.priv) {
                        pr_err("nand: error: unable to use s/w BCH library\n");
                        err = -EINVAL;
@@ -2012,6 +2015,9 @@ static int omap_nand_probe(struct platform_device *pdev)
                goto return_error;
        }
 
+       if (info->ecc_opt == OMAP_ECC_HAM1_CODE_SW)
+               goto scan_tail;
+
        /* 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 */
@@ -2021,7 +2027,9 @@ static int omap_nand_probe(struct platform_device *pdev)
                err = -EINVAL;
                goto return_error;
        }
+       nand_chip->ecc.layout = ecclayout;
 
+scan_tail:
        /* second phase scan */
        if (nand_scan_tail(mtd)) {
                err = -ENXIO;
index ee2c73a9de397da448bd3ac617b04bf1a6ae7749..5d27a6207384cc233ec9ea6051e75a33362da2ef 100644 (file)
@@ -2057,7 +2057,7 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
        struct port *port;
        bool should_notify_rtnl = BOND_SLAVE_NOTIFY_LATER;
 
-       read_lock(&bond->lock);
+       read_lock(&bond->curr_slave_lock);
        rcu_read_lock();
 
        /* check if there are any slaves */
@@ -2120,7 +2120,7 @@ re_arm:
                }
        }
        rcu_read_unlock();
-       read_unlock(&bond->lock);
+       read_unlock(&bond->curr_slave_lock);
 
        if (should_notify_rtnl && rtnl_trylock()) {
                bond_slave_state_notify(bond);
@@ -2395,7 +2395,6 @@ int __bond_3ad_get_active_agg_info(struct bonding *bond,
        return 0;
 }
 
-/* Wrapper used to hold bond->lock so no slave manipulation can occur */
 int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info)
 {
        int ret;
@@ -2487,9 +2486,9 @@ int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond,
        if (!lacpdu)
                return ret;
 
-       read_lock(&bond->lock);
+       read_lock(&bond->curr_slave_lock);
        ret = bond_3ad_rx_indication(lacpdu, slave, skb->len);
-       read_unlock(&bond->lock);
+       read_unlock(&bond->curr_slave_lock);
        return ret;
 }
 
index 95dd1f58c260d941c51ac4a369b2b97ba3f4ba34..028496205f39ec98c1b6346886f2dc4c50ef1f89 100644 (file)
@@ -1388,7 +1388,7 @@ static int bond_do_alb_xmit(struct sk_buff *skb, struct bonding *bond,
        }
 
        if (tx_slave && bond_slave_can_tx(tx_slave)) {
-               if (tx_slave != rcu_dereference(bond->curr_active_slave)) {
+               if (tx_slave != rcu_access_pointer(bond->curr_active_slave)) {
                        ether_addr_copy(eth_data->h_source,
                                        tx_slave->dev->dev_addr);
                }
@@ -1775,8 +1775,7 @@ void bond_alb_handle_link_change(struct bonding *bond, struct slave *slave, char
  * Set the bond->curr_active_slave to @new_slave and handle
  * mac address swapping and promiscuity changes as needed.
  *
- * If new_slave is NULL, caller must hold curr_slave_lock or
- * bond->lock for write.
+ * If new_slave is NULL, caller must hold curr_slave_lock for write
  *
  * If new_slave is not NULL, caller must hold RTNL, curr_slave_lock
  * for write.  Processing here may sleep, so no other locks may be held.
@@ -1857,12 +1856,8 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave
        write_lock_bh(&bond->curr_slave_lock);
 }
 
-/*
- * Called with RTNL
- */
+/* Called with RTNL */
 int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr)
-       __acquires(&bond->lock)
-       __releases(&bond->lock)
 {
        struct bonding *bond = netdev_priv(bond_dev);
        struct sockaddr *sa = addr;
@@ -1895,14 +1890,12 @@ int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr)
        } else {
                alb_set_slave_mac_addr(curr_active, bond_dev->dev_addr);
 
-               read_lock(&bond->lock);
                alb_send_learning_packets(curr_active,
                                          bond_dev->dev_addr, false);
                if (bond->alb_info.rlb_enabled) {
                        /* inform clients mac address has changed */
                        rlb_req_update_slave_clients(bond, curr_active);
                }
-               read_unlock(&bond->lock);
        }
 
        return 0;
index f0f5eab0fab102bbf3b4417632abcc5bf6082ea8..b43b2df9e5d1f2596f3d20abe60450e2c08c6cba 100644 (file)
@@ -708,7 +708,7 @@ out:
 
 static bool bond_should_change_active(struct bonding *bond)
 {
-       struct slave *prim = bond->primary_slave;
+       struct slave *prim = rtnl_dereference(bond->primary_slave);
        struct slave *curr = bond_deref_active_protected(bond);
 
        if (!prim || !curr || curr->link != BOND_LINK_UP)
@@ -732,13 +732,14 @@ static bool bond_should_change_active(struct bonding *bond)
  */
 static struct slave *bond_find_best_slave(struct bonding *bond)
 {
-       struct slave *slave, *bestslave = NULL;
+       struct slave *slave, *bestslave = NULL, *primary;
        struct list_head *iter;
        int mintime = bond->params.updelay;
 
-       if (bond->primary_slave && bond->primary_slave->link == BOND_LINK_UP &&
+       primary = rtnl_dereference(bond->primary_slave);
+       if (primary && primary->link == BOND_LINK_UP &&
            bond_should_change_active(bond))
-               return bond->primary_slave;
+               return primary;
 
        bond_for_each_slave(bond, slave, iter) {
                if (slave->link == BOND_LINK_UP)
@@ -1482,7 +1483,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
        if (bond_uses_primary(bond) && bond->params.primary[0]) {
                /* if there is a primary slave, remember it */
                if (strcmp(bond->params.primary, new_slave->dev->name) == 0) {
-                       bond->primary_slave = new_slave;
+                       rcu_assign_pointer(bond->primary_slave, new_slave);
                        bond->force_primary = true;
                }
        }
@@ -1596,8 +1597,8 @@ err_detach:
                bond_hw_addr_flush(bond_dev, slave_dev);
 
        vlan_vids_del_by_dev(slave_dev, bond_dev);
-       if (bond->primary_slave == new_slave)
-               bond->primary_slave = NULL;
+       if (rcu_access_pointer(bond->primary_slave) == new_slave)
+               RCU_INIT_POINTER(bond->primary_slave, NULL);
        if (rcu_access_pointer(bond->curr_active_slave) == new_slave) {
                block_netpoll_tx();
                write_lock_bh(&bond->curr_slave_lock);
@@ -1606,6 +1607,8 @@ err_detach:
                write_unlock_bh(&bond->curr_slave_lock);
                unblock_netpoll_tx();
        }
+       /* either primary_slave or curr_active_slave might've changed */
+       synchronize_rcu();
        slave_disable_netpoll(new_slave);
 
 err_close:
@@ -1687,13 +1690,15 @@ static int __bond_release_one(struct net_device *bond_dev,
         * for this slave anymore.
         */
        netdev_rx_handler_unregister(slave_dev);
-       write_lock_bh(&bond->lock);
 
-       /* Inform AD package of unbinding of slave. */
-       if (BOND_MODE(bond) == BOND_MODE_8023AD)
+       if (BOND_MODE(bond) == BOND_MODE_8023AD) {
+               /* Sync against bond_3ad_rx_indication and
+                * bond_3ad_state_machine_handler
+                */
+               write_lock_bh(&bond->curr_slave_lock);
                bond_3ad_unbind_slave(slave);
-
-       write_unlock_bh(&bond->lock);
+               write_unlock_bh(&bond->curr_slave_lock);
+       }
 
        netdev_info(bond_dev, "Releasing %s interface %s\n",
                    bond_is_active_slave(slave) ? "active" : "backup",
@@ -1712,8 +1717,8 @@ static int __bond_release_one(struct net_device *bond_dev,
                                    bond_dev->name, slave_dev->name);
        }
 
-       if (bond->primary_slave == slave)
-               bond->primary_slave = NULL;
+       if (rtnl_dereference(bond->primary_slave) == slave)
+               RCU_INIT_POINTER(bond->primary_slave, NULL);
 
        if (oldcurrent == slave) {
                write_lock_bh(&bond->curr_slave_lock);
@@ -1974,7 +1979,7 @@ static int bond_miimon_inspect(struct bonding *bond)
 static void bond_miimon_commit(struct bonding *bond)
 {
        struct list_head *iter;
-       struct slave *slave;
+       struct slave *slave, *primary;
 
        bond_for_each_slave(bond, slave, iter) {
                switch (slave->new_link) {
@@ -1985,13 +1990,14 @@ static void bond_miimon_commit(struct bonding *bond)
                        slave->link = BOND_LINK_UP;
                        slave->last_link_up = jiffies;
 
+                       primary = rtnl_dereference(bond->primary_slave);
                        if (BOND_MODE(bond) == BOND_MODE_8023AD) {
                                /* prevent it from being the active one */
                                bond_set_backup_slave(slave);
                        } else if (BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP) {
                                /* make it immediately active */
                                bond_set_active_slave(slave);
-                       } else if (slave != bond->primary_slave) {
+                       } else if (slave != primary) {
                                /* prevent it from being the active one */
                                bond_set_backup_slave(slave);
                        }
@@ -2009,8 +2015,7 @@ static void bond_miimon_commit(struct bonding *bond)
                                bond_alb_handle_link_change(bond, slave,
                                                            BOND_LINK_UP);
 
-                       if (!bond->curr_active_slave ||
-                           (slave == bond->primary_slave))
+                       if (!bond->curr_active_slave || slave == primary)
                                goto do_failover;
 
                        continue;
@@ -2631,7 +2636,7 @@ static void bond_ab_arp_commit(struct bonding *bond)
                                            slave->dev->name);
 
                                if (!rtnl_dereference(bond->curr_active_slave) ||
-                                   (slave == bond->primary_slave))
+                                   slave == rtnl_dereference(bond->primary_slave))
                                        goto do_failover;
 
                        }
@@ -2858,7 +2863,7 @@ static int bond_master_netdev_event(unsigned long event,
 static int bond_slave_netdev_event(unsigned long event,
                                   struct net_device *slave_dev)
 {
-       struct slave *slave = bond_slave_get_rtnl(slave_dev);
+       struct slave *slave = bond_slave_get_rtnl(slave_dev), *primary;
        struct bonding *bond;
        struct net_device *bond_dev;
        u32 old_speed;
@@ -2872,6 +2877,7 @@ static int bond_slave_netdev_event(unsigned long event,
                return NOTIFY_DONE;
        bond_dev = slave->bond->dev;
        bond = slave->bond;
+       primary = rtnl_dereference(bond->primary_slave);
 
        switch (event) {
        case NETDEV_UNREGISTER:
@@ -2919,18 +2925,18 @@ static int bond_slave_netdev_event(unsigned long event,
                    !bond->params.primary[0])
                        break;
 
-               if (slave == bond->primary_slave) {
+               if (slave == primary) {
                        /* slave's name changed - he's no longer primary */
-                       bond->primary_slave = NULL;
+                       RCU_INIT_POINTER(bond->primary_slave, NULL);
                } else if (!strcmp(slave_dev->name, bond->params.primary)) {
                        /* we have a new primary slave */
-                       bond->primary_slave = slave;
+                       rcu_assign_pointer(bond->primary_slave, slave);
                } else { /* we didn't change primary - exit */
                        break;
                }
 
                netdev_info(bond->dev, "Primary slave changed to %s, reselecting active slave\n",
-                           bond->primary_slave ? slave_dev->name : "none");
+                           primary ? slave_dev->name : "none");
 
                block_netpoll_tx();
                write_lock_bh(&bond->curr_slave_lock);
@@ -3099,7 +3105,6 @@ static int bond_open(struct net_device *bond_dev)
        struct slave *slave;
 
        /* reset slave->backup and slave->inactive */
-       read_lock(&bond->lock);
        if (bond_has_slaves(bond)) {
                read_lock(&bond->curr_slave_lock);
                bond_for_each_slave(bond, slave, iter) {
@@ -3114,7 +3119,6 @@ static int bond_open(struct net_device *bond_dev)
                }
                read_unlock(&bond->curr_slave_lock);
        }
-       read_unlock(&bond->lock);
 
        bond_work_init_all(bond);
 
@@ -3169,7 +3173,6 @@ static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev,
 
        memset(stats, 0, sizeof(*stats));
 
-       read_lock_bh(&bond->lock);
        bond_for_each_slave(bond, slave, iter) {
                const struct rtnl_link_stats64 *sstats =
                        dev_get_stats(slave->dev, &temp);
@@ -3200,7 +3203,6 @@ static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev,
                stats->tx_heartbeat_errors += sstats->tx_heartbeat_errors;
                stats->tx_window_errors += sstats->tx_window_errors;
        }
-       read_unlock_bh(&bond->lock);
 
        return stats;
 }
@@ -3240,13 +3242,11 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd
 
                if (mii->reg_num == 1) {
                        mii->val_out = 0;
-                       read_lock(&bond->lock);
                        read_lock(&bond->curr_slave_lock);
                        if (netif_carrier_ok(bond->dev))
                                mii->val_out = BMSR_LSTATUS;
 
                        read_unlock(&bond->curr_slave_lock);
-                       read_unlock(&bond->lock);
                }
 
                return 0;
@@ -3422,21 +3422,6 @@ static int bond_change_mtu(struct net_device *bond_dev, int new_mtu)
 
        netdev_dbg(bond_dev, "bond=%p, new_mtu=%d\n", bond, new_mtu);
 
-       /* Can't hold bond->lock with bh disabled here since
-        * some base drivers panic. On the other hand we can't
-        * hold bond->lock without bh disabled because we'll
-        * deadlock. The only solution is to rely on the fact
-        * that we're under rtnl_lock here, and the slaves
-        * list won't change. This doesn't solve the problem
-        * of setting the slave's MTU while it is
-        * transmitting, but the assumption is that the base
-        * driver can handle that.
-        *
-        * TODO: figure out a way to safely iterate the slaves
-        * list, but without holding a lock around the actual
-        * call to the base driver.
-        */
-
        bond_for_each_slave(bond, slave, iter) {
                netdev_dbg(bond_dev, "s %p c_m %p\n",
                           slave, slave->dev->netdev_ops->ndo_change_mtu);
@@ -3511,21 +3496,6 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr)
        if (!is_valid_ether_addr(sa->sa_data))
                return -EADDRNOTAVAIL;
 
-       /* Can't hold bond->lock with bh disabled here since
-        * some base drivers panic. On the other hand we can't
-        * hold bond->lock without bh disabled because we'll
-        * deadlock. The only solution is to rely on the fact
-        * that we're under rtnl_lock here, and the slaves
-        * list won't change. This doesn't solve the problem
-        * of setting the slave's hw address while it is
-        * transmitting, but the assumption is that the base
-        * driver can handle that.
-        *
-        * TODO: figure out a way to safely iterate the slaves
-        * list, but without holding a lock around the actual
-        * call to the base driver.
-        */
-
        bond_for_each_slave(bond, slave, iter) {
                netdev_dbg(bond_dev, "slave %p %s\n", slave, slave->dev->name);
                res = dev_set_mac_address(slave->dev, addr);
@@ -3851,7 +3821,6 @@ static int bond_ethtool_get_settings(struct net_device *bond_dev,
         * the true receive or transmit bandwidth (not all modes are symmetric)
         * this is an accurate maximum.
         */
-       read_lock(&bond->lock);
        bond_for_each_slave(bond, slave, iter) {
                if (bond_slave_can_tx(slave)) {
                        if (slave->speed != SPEED_UNKNOWN)
@@ -3862,7 +3831,6 @@ static int bond_ethtool_get_settings(struct net_device *bond_dev,
                }
        }
        ethtool_cmd_speed_set(ecmd, speed ? : SPEED_UNKNOWN);
-       read_unlock(&bond->lock);
 
        return 0;
 }
@@ -3925,7 +3893,6 @@ void bond_setup(struct net_device *bond_dev)
        struct bonding *bond = netdev_priv(bond_dev);
 
        /* initialize rwlocks */
-       rwlock_init(&bond->lock);
        rwlock_init(&bond->curr_slave_lock);
        bond->params = bonding_defaults;
 
index d163e112f04ce00956fedd17221c3c283ff8a3c6..c13d83e15ace440fc624ff6913d617fdabd2699f 100644 (file)
@@ -96,6 +96,10 @@ static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = {
        [IFLA_BOND_AD_INFO]             = { .type = NLA_NESTED },
 };
 
+static const struct nla_policy bond_slave_policy[IFLA_BOND_SLAVE_MAX + 1] = {
+       [IFLA_BOND_SLAVE_QUEUE_ID]      = { .type = NLA_U16 },
+};
+
 static int bond_validate(struct nlattr *tb[], struct nlattr *data[])
 {
        if (tb[IFLA_ADDRESS]) {
@@ -107,6 +111,33 @@ static int bond_validate(struct nlattr *tb[], struct nlattr *data[])
        return 0;
 }
 
+static int bond_slave_changelink(struct net_device *bond_dev,
+                                struct net_device *slave_dev,
+                                struct nlattr *tb[], struct nlattr *data[])
+{
+       struct bonding *bond = netdev_priv(bond_dev);
+       struct bond_opt_value newval;
+       int err;
+
+       if (!data)
+               return 0;
+
+       if (data[IFLA_BOND_SLAVE_QUEUE_ID]) {
+               u16 queue_id = nla_get_u16(data[IFLA_BOND_SLAVE_QUEUE_ID]);
+               char queue_id_str[IFNAMSIZ + 7];
+
+               /* queue_id option setting expects slave_name:queue_id */
+               snprintf(queue_id_str, sizeof(queue_id_str), "%s:%u\n",
+                        slave_dev->name, queue_id);
+               bond_opt_initstr(&newval, queue_id_str);
+               err = __bond_opt_set(bond, BOND_OPT_QUEUE_ID, &newval);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
 static int bond_changelink(struct net_device *bond_dev,
                           struct nlattr *tb[], struct nlattr *data[])
 {
@@ -412,6 +443,7 @@ static int bond_fill_info(struct sk_buff *skb,
        unsigned int packets_per_slave;
        int ifindex, i, targets_added;
        struct nlattr *targets;
+       struct slave *primary;
 
        if (nla_put_u8(skb, IFLA_BOND_MODE, BOND_MODE(bond)))
                goto nla_put_failure;
@@ -461,9 +493,9 @@ static int bond_fill_info(struct sk_buff *skb,
                        bond->params.arp_all_targets))
                goto nla_put_failure;
 
-       if (bond->primary_slave &&
-           nla_put_u32(skb, IFLA_BOND_PRIMARY,
-                       bond->primary_slave->dev->ifindex))
+       primary = rtnl_dereference(bond->primary_slave);
+       if (primary &&
+           nla_put_u32(skb, IFLA_BOND_PRIMARY, primary->dev->ifindex))
                goto nla_put_failure;
 
        if (nla_put_u8(skb, IFLA_BOND_PRIMARY_RESELECT,
@@ -562,6 +594,9 @@ struct rtnl_link_ops bond_link_ops __read_mostly = {
        .get_num_tx_queues      = bond_get_num_tx_queues,
        .get_num_rx_queues      = bond_get_num_tx_queues, /* Use the same number
                                                             as for TX queues */
+       .slave_maxtype          = IFLA_BOND_SLAVE_MAX,
+       .slave_policy           = bond_slave_policy,
+       .slave_changelink       = bond_slave_changelink,
        .get_slave_size         = bond_get_slave_size,
        .fill_slave_info        = bond_fill_slave_info,
 };
index dc73463c2c237d99bf26c9b3ff21512c36f69504..534c0600484e95e6414d4ba4308590aca1e53d3b 100644 (file)
@@ -625,6 +625,8 @@ int __bond_opt_set(struct bonding *bond,
 out:
        if (ret)
                bond_opt_error_interpret(bond, opt, ret, val);
+       else
+               call_netdevice_notifiers(NETDEV_CHANGEINFODATA, bond->dev);
 
        return ret;
 }
@@ -953,14 +955,7 @@ static 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;
-
-       /* not to race with bond_arp_rcv */
-       write_lock_bh(&bond->lock);
-       ret = _bond_option_arp_ip_target_add(bond, target);
-       write_unlock_bh(&bond->lock);
-
-       return ret;
+       return _bond_option_arp_ip_target_add(bond, target);
 }
 
 static int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target)
@@ -989,9 +984,6 @@ static int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target)
 
        netdev_info(bond->dev, "Removing ARP target %pI4\n", &target);
 
-       /* not to race with bond_arp_rcv */
-       write_lock_bh(&bond->lock);
-
        bond_for_each_slave(bond, slave, iter) {
                targets_rx = slave->target_last_arp_rx;
                for (i = ind; (i < BOND_MAX_ARP_TARGETS-1) && targets[i+1]; i++)
@@ -1002,8 +994,6 @@ static int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target)
                targets[i] = targets[i+1];
        targets[i] = 0;
 
-       write_unlock_bh(&bond->lock);
-
        return 0;
 }
 
@@ -1011,11 +1001,8 @@ void bond_option_arp_ip_targets_clear(struct bonding *bond)
 {
        int i;
 
-       /* not to race with bond_arp_rcv */
-       write_lock_bh(&bond->lock);
        for (i = 0; i < BOND_MAX_ARP_TARGETS; i++)
                _bond_options_arp_ip_target_set(bond, i, 0, 0);
-       write_unlock_bh(&bond->lock);
 }
 
 static int bond_option_arp_ip_targets_set(struct bonding *bond,
@@ -1079,7 +1066,6 @@ static int bond_option_primary_set(struct bonding *bond,
        struct slave *slave;
 
        block_netpoll_tx();
-       read_lock(&bond->lock);
        write_lock_bh(&bond->curr_slave_lock);
 
        p = strchr(primary, '\n');
@@ -1088,7 +1074,7 @@ static int bond_option_primary_set(struct bonding *bond,
        /* check to see if we are clearing primary */
        if (!strlen(primary)) {
                netdev_info(bond->dev, "Setting primary slave to None\n");
-               bond->primary_slave = NULL;
+               RCU_INIT_POINTER(bond->primary_slave, NULL);
                memset(bond->params.primary, 0, sizeof(bond->params.primary));
                bond_select_active_slave(bond);
                goto out;
@@ -1098,16 +1084,16 @@ static int bond_option_primary_set(struct bonding *bond,
                if (strncmp(slave->dev->name, primary, IFNAMSIZ) == 0) {
                        netdev_info(bond->dev, "Setting %s as primary slave\n",
                                    slave->dev->name);
-                       bond->primary_slave = slave;
+                       rcu_assign_pointer(bond->primary_slave, slave);
                        strcpy(bond->params.primary, slave->dev->name);
                        bond_select_active_slave(bond);
                        goto out;
                }
        }
 
-       if (bond->primary_slave) {
+       if (rtnl_dereference(bond->primary_slave)) {
                netdev_info(bond->dev, "Setting primary slave to None\n");
-               bond->primary_slave = NULL;
+               RCU_INIT_POINTER(bond->primary_slave, NULL);
                bond_select_active_slave(bond);
        }
        strncpy(bond->params.primary, primary, IFNAMSIZ);
@@ -1118,7 +1104,6 @@ static int bond_option_primary_set(struct bonding *bond,
 
 out:
        write_unlock_bh(&bond->curr_slave_lock);
-       read_unlock(&bond->lock);
        unblock_netpoll_tx();
 
        return 0;
index de62c0385dfb06309a5fa4b4aff3f524a099ebe3..bb09d0442aa88e0d7a989bf4594551f5d66bbee5 100644 (file)
@@ -7,21 +7,18 @@
 
 static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos)
        __acquires(RCU)
-       __acquires(&bond->lock)
 {
        struct bonding *bond = seq->private;
        struct list_head *iter;
        struct slave *slave;
        loff_t off = 0;
 
-       /* make sure the bond won't be taken away */
        rcu_read_lock();
-       read_lock(&bond->lock);
 
        if (*pos == 0)
                return SEQ_START_TOKEN;
 
-       bond_for_each_slave(bond, slave, iter)
+       bond_for_each_slave_rcu(bond, slave, iter)
                if (++off == *pos)
                        return slave;
 
@@ -37,12 +34,9 @@ static void *bond_info_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 
        ++*pos;
        if (v == SEQ_START_TOKEN)
-               return bond_first_slave(bond);
+               return bond_first_slave_rcu(bond);
 
-       if (bond_is_last_slave(bond, v))
-               return NULL;
-
-       bond_for_each_slave(bond, slave, iter) {
+       bond_for_each_slave_rcu(bond, slave, iter) {
                if (found)
                        return slave;
                if (slave == v)
@@ -53,12 +47,8 @@ static void *bond_info_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 }
 
 static void bond_info_seq_stop(struct seq_file *seq, void *v)
-       __releases(&bond->lock)
        __releases(RCU)
 {
-       struct bonding *bond = seq->private;
-
-       read_unlock(&bond->lock);
        rcu_read_unlock();
 }
 
@@ -66,7 +56,7 @@ static void bond_info_show_master(struct seq_file *seq)
 {
        struct bonding *bond = seq->private;
        const struct bond_opt_value *optval;
-       struct slave *curr;
+       struct slave *curr, *primary;
        int i;
 
        curr = rcu_dereference(bond->curr_active_slave);
@@ -92,10 +82,10 @@ static void bond_info_show_master(struct seq_file *seq)
        }
 
        if (bond_uses_primary(bond)) {
+               primary = rcu_dereference(bond->primary_slave);
                seq_printf(seq, "Primary Slave: %s",
-                          (bond->primary_slave) ?
-                          bond->primary_slave->dev->name : "None");
-               if (bond->primary_slave) {
+                          primary ? primary->dev->name : "None");
+               if (primary) {
                        optval = bond_opt_get_val(BOND_OPT_PRIMARY_RESELECT,
                                                  bond->params.primary_reselect);
                        seq_printf(seq, " (primary_reselect %s)",
index 98db8edd9c755c55d04a26b0b40143ba80d15a55..5555517284db6916ce4982684776376d37e768b5 100644 (file)
@@ -425,11 +425,15 @@ static ssize_t bonding_show_primary(struct device *d,
                                    struct device_attribute *attr,
                                    char *buf)
 {
-       int count = 0;
        struct bonding *bond = to_bond(d);
+       struct slave *primary;
+       int count = 0;
 
-       if (bond->primary_slave)
-               count = sprintf(buf, "%s\n", bond->primary_slave->dev->name);
+       rcu_read_lock();
+       primary = rcu_dereference(bond->primary_slave);
+       if (primary)
+               count = sprintf(buf, "%s\n", primary->dev->name);
+       rcu_read_unlock();
 
        return count;
 }
index aace510d08d1dae8b300528ab703452bbe5c99e5..78c461abaa09a369ffe63f72310c1784acc676b6 100644 (file)
@@ -83,7 +83,7 @@
  * @pos:       current slave
  * @iter:      list_head * iterator
  *
- * Caller must hold bond->lock
+ * Caller must hold RTNL
  */
 #define bond_for_each_slave(bond, pos, iter) \
        netdev_for_each_lower_private((bond)->dev, pos, iter)
@@ -185,22 +185,18 @@ struct slave {
 /*
  * Here are the locking policies for the two bonding locks:
  *
- * 1) Get bond->lock when reading/writing slave list.
+ * 1) Get rcu_read_lock when reading or RTNL when writing slave list.
  * 2) Get bond->curr_slave_lock when reading/writing bond->curr_active_slave.
- *    (It is unnecessary when the write-lock is put with bond->lock.)
- * 3) When we lock with bond->curr_slave_lock, we must lock with bond->lock
- *    beforehand.
  */
 struct bonding {
        struct   net_device *dev; /* first - useful for panic debug */
        struct   slave __rcu *curr_active_slave;
        struct   slave __rcu *current_arp_slave;
-       struct   slave *primary_slave;
+       struct   slave __rcu *primary_slave;
        bool     force_primary;
        s32      slave_cnt; /* never change this value outside the attach/detach wrappers */
        int     (*recv_probe)(const struct sk_buff *, struct bonding *,
                              struct slave *);
-       rwlock_t lock;
        rwlock_t curr_slave_lock;
        u8       send_peer_notif;
        u8       igmp_retrans;
index 41688229c570eb92e9e79b2bee2bd5b9d6173e39..e78d6b32431d6ce509a8e219114af5c9e5789779 100644 (file)
@@ -143,6 +143,8 @@ source "drivers/net/can/sja1000/Kconfig"
 
 source "drivers/net/can/c_can/Kconfig"
 
+source "drivers/net/can/m_can/Kconfig"
+
 source "drivers/net/can/cc770/Kconfig"
 
 source "drivers/net/can/spi/Kconfig"
index 1697f22353a943315bdb5e162d3cdce4f7d535f7..fc9304143f449c8eee3aaddcaf1d701fc90b7bb5 100644 (file)
@@ -17,6 +17,7 @@ obj-y                         += softing/
 obj-$(CONFIG_CAN_SJA1000)      += sja1000/
 obj-$(CONFIG_CAN_MSCAN)                += mscan/
 obj-$(CONFIG_CAN_C_CAN)                += c_can/
+obj-$(CONFIG_CAN_M_CAN)                += m_can/
 obj-$(CONFIG_CAN_CC770)                += cc770/
 obj-$(CONFIG_CAN_AT91)         += at91_can.o
 obj-$(CONFIG_CAN_TI_HECC)      += ti_hecc.o
@@ -28,4 +29,4 @@ obj-$(CONFIG_CAN_GRCAN)               += grcan.o
 obj-$(CONFIG_CAN_RCAR)         += rcar_can.o
 obj-$(CONFIG_CAN_XILINXCAN)    += xilinx_can.o
 
-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
+subdir-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
index ad1cc842170add4076f17ec08c211bc16b7b647b..9fdc678b5b3787776a94371215a11f2a3d5194f3 100644 (file)
@@ -5,5 +5,3 @@
 obj-$(CONFIG_CAN_C_CAN) += c_can.o
 obj-$(CONFIG_CAN_C_CAN_PLATFORM) += c_can_platform.o
 obj-$(CONFIG_CAN_C_CAN_PCI) += c_can_pci.o
-
-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
index 5dede6e6437619f455f19ef6f8277e74e7639997..109cb44291f51f3af4c45979aa3b3ef53099d061 100644 (file)
@@ -280,7 +280,7 @@ static int c_can_plat_probe(struct platform_device *pdev)
 
                priv->raminit_ctrlreg = devm_ioremap(&pdev->dev, res->start,
                                                     resource_size(res));
-               if (IS_ERR(priv->raminit_ctrlreg) || priv->instance < 0)
+               if (!priv->raminit_ctrlreg || priv->instance < 0)
                        dev_info(&pdev->dev, "control memory is not used for raminit\n");
                else
                        priv->raminit = c_can_hw_raminit_ti;
index 9fb8321b33eb770c16090963b02d45720e26f8af..8657f879ae19084cbd9143c62e72f72dfea9fe91 100644 (file)
@@ -5,5 +5,3 @@
 obj-$(CONFIG_CAN_CC770) += cc770.o
 obj-$(CONFIG_CAN_CC770_ISA) += cc770_isa.o
 obj-$(CONFIG_CAN_CC770_PLATFORM) += cc770_platform.o
-
-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
index 9f91fcba43f8718f4d546e39faaef1aa3bd9fabf..02492d241e4c9e8cb8d49ae319067c7c0aa1f9cf 100644 (file)
@@ -103,11 +103,11 @@ 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);
-       long rate, best_rate = 0;
        long best_error = 1000000000, error = 0;
        int best_tseg = 0, best_brp = 0, brp = 0;
        int tsegall, tseg = 0, tseg1 = 0, tseg2 = 0;
        int spt_error = 1000, spt = 0, sampl_pt;
+       long rate;
        u64 v64;
 
        /* Use CIA recommended sample points */
@@ -152,7 +152,6 @@ static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
                }
                best_tseg = tseg / 2;
                best_brp = brp;
-               best_rate = rate;
                if (error == 0)
                        break;
        }
index f425ec2c7839de4abe1a481cf94d0fd03435c845..2700865efcad5d73ab7ba244abdef3fe6917c395 100644 (file)
 #define FLEXCAN_CTRL_ERR_ALL \
        (FLEXCAN_CTRL_ERR_BUS | FLEXCAN_CTRL_ERR_STATE)
 
+/* FLEXCAN control register 2 (CTRL2) bits */
+#define FLEXCAN_CRL2_ECRWRE            BIT(29)
+#define FLEXCAN_CRL2_WRMFRZ            BIT(28)
+#define FLEXCAN_CRL2_RFFN(x)           (((x) & 0x0f) << 24)
+#define FLEXCAN_CRL2_TASD(x)           (((x) & 0x1f) << 19)
+#define FLEXCAN_CRL2_MRP               BIT(18)
+#define FLEXCAN_CRL2_RRS               BIT(17)
+#define FLEXCAN_CRL2_EACEN             BIT(16)
+
+/* FLEXCAN memory error control register (MECR) bits */
+#define FLEXCAN_MECR_ECRWRDIS          BIT(31)
+#define FLEXCAN_MECR_HANCEI_MSK                BIT(19)
+#define FLEXCAN_MECR_FANCEI_MSK                BIT(18)
+#define FLEXCAN_MECR_CEI_MSK           BIT(16)
+#define FLEXCAN_MECR_HAERRIE           BIT(15)
+#define FLEXCAN_MECR_FAERRIE           BIT(14)
+#define FLEXCAN_MECR_EXTERRIE          BIT(13)
+#define FLEXCAN_MECR_RERRDIS           BIT(9)
+#define FLEXCAN_MECR_ECCDIS            BIT(8)
+#define FLEXCAN_MECR_NCEFAFRZ          BIT(7)
+
 /* FLEXCAN error and status register (ESR) bits */
 #define FLEXCAN_ESR_TWRN_INT           BIT(17)
 #define FLEXCAN_ESR_RWRN_INT           BIT(16)
  * FLEXCAN hardware feature flags
  *
  * Below is some version info we got:
- *    SOC   Version   IP-Version  Glitch-  [TR]WRN_INT
- *                                Filter?   connected?
- *   MX25  FlexCAN2  03.00.00.00     no         no
- *   MX28  FlexCAN2  03.00.04.00    yes        yes
- *   MX35  FlexCAN2  03.00.00.00     no         no
- *   MX53  FlexCAN2  03.00.00.00    yes         no
- *   MX6s  FlexCAN3  10.00.12.00    yes        yes
+ *    SOC   Version   IP-Version  Glitch-  [TR]WRN_INT  Memory err
+ *                                Filter?   connected?  detection
+ *   MX25  FlexCAN2  03.00.00.00     no         no         no
+ *   MX28  FlexCAN2  03.00.04.00    yes        yes         no
+ *   MX35  FlexCAN2  03.00.00.00     no         no         no
+ *   MX53  FlexCAN2  03.00.00.00    yes         no         no
+ *   MX6s  FlexCAN3  10.00.12.00    yes        yes         no
+ *   VF610 FlexCAN3  ?               no        yes        yes
  *
  * Some SOCs do not have the RX_WARN & TX_WARN interrupt line connected.
  */
 #define FLEXCAN_HAS_V10_FEATURES       BIT(1) /* For core version >= 10 */
 #define FLEXCAN_HAS_BROKEN_ERR_STATE   BIT(2) /* [TR]WRN_INT not connected */
+#define FLEXCAN_HAS_MECR_FEATURES      BIT(3) /* Memory error detection */
 
 /* Structure of the message buffer */
 struct flexcan_mb {
@@ -192,8 +215,17 @@ struct flexcan_regs {
        u32 crcr;               /* 0x44 */
        u32 rxfgmask;           /* 0x48 */
        u32 rxfir;              /* 0x4c */
-       u32 _reserved3[12];
-       struct flexcan_mb cantxfg[64];
+       u32 _reserved3[12];     /* 0x50 */
+       struct flexcan_mb cantxfg[64];  /* 0x80 */
+       u32 _reserved4[408];
+       u32 mecr;               /* 0xae0 */
+       u32 erriar;             /* 0xae4 */
+       u32 erridpr;            /* 0xae8 */
+       u32 errippr;            /* 0xaec */
+       u32 rerrar;             /* 0xaf0 */
+       u32 rerrdr;             /* 0xaf4 */
+       u32 rerrsynr;           /* 0xaf8 */
+       u32 errsr;              /* 0xafc */
 };
 
 struct flexcan_devtype_data {
@@ -223,6 +255,9 @@ static struct flexcan_devtype_data fsl_imx28_devtype_data;
 static struct flexcan_devtype_data fsl_imx6q_devtype_data = {
        .features = FLEXCAN_HAS_V10_FEATURES,
 };
+static struct flexcan_devtype_data fsl_vf610_devtype_data = {
+       .features = FLEXCAN_HAS_V10_FEATURES | FLEXCAN_HAS_MECR_FEATURES,
+};
 
 static const struct can_bittiming_const flexcan_bittiming_const = {
        .name = DRV_NAME,
@@ -378,8 +413,9 @@ static int flexcan_chip_softreset(struct flexcan_priv *priv)
        return 0;
 }
 
-static int flexcan_get_berr_counter(const struct net_device *dev,
-                                   struct can_berr_counter *bec)
+
+static int __flexcan_get_berr_counter(const struct net_device *dev,
+                                     struct can_berr_counter *bec)
 {
        const struct flexcan_priv *priv = netdev_priv(dev);
        struct flexcan_regs __iomem *regs = priv->base;
@@ -391,6 +427,29 @@ static int flexcan_get_berr_counter(const struct net_device *dev,
        return 0;
 }
 
+static int flexcan_get_berr_counter(const struct net_device *dev,
+                                   struct can_berr_counter *bec)
+{
+       const struct flexcan_priv *priv = netdev_priv(dev);
+       int err;
+
+       err = clk_prepare_enable(priv->clk_ipg);
+       if (err)
+               return err;
+
+       err = clk_prepare_enable(priv->clk_per);
+       if (err)
+               goto out_disable_ipg;
+
+       err = __flexcan_get_berr_counter(dev, bec);
+
+       clk_disable_unprepare(priv->clk_per);
+ out_disable_ipg:
+       clk_disable_unprepare(priv->clk_ipg);
+
+       return err;
+}
+
 static int flexcan_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        const struct flexcan_priv *priv = netdev_priv(dev);
@@ -503,7 +562,7 @@ static void do_state(struct net_device *dev,
        struct flexcan_priv *priv = netdev_priv(dev);
        struct can_berr_counter bec;
 
-       flexcan_get_berr_counter(dev, &bec);
+       __flexcan_get_berr_counter(dev, &bec);
 
        switch (priv->can.state) {
        case CAN_STATE_ERROR_ACTIVE:
@@ -549,6 +608,13 @@ static void do_state(struct net_device *dev,
 
        /* process state changes depending on the new state */
        switch (new_state) {
+       case CAN_STATE_ERROR_WARNING:
+               netdev_dbg(dev, "Error Warning\n");
+               cf->can_id |= CAN_ERR_CRTL;
+               cf->data[1] = (bec.txerr > bec.rxerr) ?
+                       CAN_ERR_CRTL_TX_WARNING :
+                       CAN_ERR_CRTL_RX_WARNING;
+               break;
        case CAN_STATE_ERROR_ACTIVE:
                netdev_dbg(dev, "Error Active\n");
                cf->can_id |= CAN_ERR_PROT;
@@ -793,7 +859,7 @@ static int flexcan_chip_start(struct net_device *dev)
        struct flexcan_priv *priv = netdev_priv(dev);
        struct flexcan_regs __iomem *regs = priv->base;
        int err;
-       u32 reg_mcr, reg_ctrl;
+       u32 reg_mcr, reg_ctrl, reg_crl2, reg_mecr;
 
        /* enable module */
        err = flexcan_chip_enable(priv);
@@ -852,6 +918,8 @@ static int flexcan_chip_start(struct net_device *dev)
        if (priv->devtype_data->features & FLEXCAN_HAS_BROKEN_ERR_STATE ||
            priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
                reg_ctrl |= FLEXCAN_CTRL_ERR_MSK;
+       else
+               reg_ctrl &= ~FLEXCAN_CTRL_ERR_MSK;
 
        /* save for later use */
        priv->reg_ctrl_default = reg_ctrl;
@@ -870,6 +938,31 @@ static int flexcan_chip_start(struct net_device *dev)
        if (priv->devtype_data->features & FLEXCAN_HAS_V10_FEATURES)
                flexcan_write(0x0, &regs->rxfgmask);
 
+       /*
+        * On Vybrid, disable memory error detection interrupts
+        * and freeze mode.
+        * This also works around errata e5295 which generates
+        * false positive memory errors and put the device in
+        * freeze mode.
+        */
+       if (priv->devtype_data->features & FLEXCAN_HAS_MECR_FEATURES) {
+               /*
+                * Follow the protocol as described in "Detection
+                * and Correction of Memory Errors" to write to
+                * MECR register
+                */
+               reg_crl2 = flexcan_read(&regs->crl2);
+               reg_crl2 |= FLEXCAN_CRL2_ECRWRE;
+               flexcan_write(reg_crl2, &regs->crl2);
+
+               reg_mecr = flexcan_read(&regs->mecr);
+               reg_mecr &= ~FLEXCAN_MECR_ECRWRDIS;
+               flexcan_write(reg_mecr, &regs->mecr);
+               reg_mecr &= ~(FLEXCAN_MECR_NCEFAFRZ | FLEXCAN_MECR_HANCEI_MSK |
+                               FLEXCAN_MECR_FANCEI_MSK);
+               flexcan_write(reg_mecr, &regs->mecr);
+       }
+
        err = flexcan_transceiver_enable(priv);
        if (err)
                goto out_chip_disable;
@@ -1080,6 +1173,7 @@ static const struct of_device_id flexcan_of_match[] = {
        { .compatible = "fsl,imx6q-flexcan", .data = &fsl_imx6q_devtype_data, },
        { .compatible = "fsl,imx28-flexcan", .data = &fsl_imx28_devtype_data, },
        { .compatible = "fsl,p1010-flexcan", .data = &fsl_p1010_devtype_data, },
+       { .compatible = "fsl,vf610-flexcan", .data = &fsl_vf610_devtype_data, },
        { /* sentinel */ },
 };
 MODULE_DEVICE_TABLE(of, flexcan_of_match);
diff --git a/drivers/net/can/m_can/Kconfig b/drivers/net/can/m_can/Kconfig
new file mode 100644 (file)
index 0000000..fca5482
--- /dev/null
@@ -0,0 +1,4 @@
+config CAN_M_CAN
+       tristate "Bosch M_CAN devices"
+       ---help---
+         Say Y here if you want to support for Bosch M_CAN controller.
diff --git a/drivers/net/can/m_can/Makefile b/drivers/net/can/m_can/Makefile
new file mode 100644 (file)
index 0000000..8bbd7f2
--- /dev/null
@@ -0,0 +1,5 @@
+#
+#  Makefile for the Bosch M_CAN controller driver.
+#
+
+obj-$(CONFIG_CAN_M_CAN) += m_can.o
diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c
new file mode 100644 (file)
index 0000000..10d571e
--- /dev/null
@@ -0,0 +1,1202 @@
+/*
+ * CAN bus driver for Bosch M_CAN controller
+ *
+ * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ *     Dong Aisheng <b29396@freescale.com>
+ *
+ * Bosch M_CAN user manual can be obtained from:
+ * http://www.bosch-semiconductors.de/media/pdf_1/ipmodules_1/m_can/
+ * mcan_users_manual_v302.pdf
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#include <linux/can/dev.h>
+
+/* napi related */
+#define M_CAN_NAPI_WEIGHT      64
+
+/* message ram configuration data length */
+#define MRAM_CFG_LEN   8
+
+/* registers definition */
+enum m_can_reg {
+       M_CAN_CREL      = 0x0,
+       M_CAN_ENDN      = 0x4,
+       M_CAN_CUST      = 0x8,
+       M_CAN_FBTP      = 0xc,
+       M_CAN_TEST      = 0x10,
+       M_CAN_RWD       = 0x14,
+       M_CAN_CCCR      = 0x18,
+       M_CAN_BTP       = 0x1c,
+       M_CAN_TSCC      = 0x20,
+       M_CAN_TSCV      = 0x24,
+       M_CAN_TOCC      = 0x28,
+       M_CAN_TOCV      = 0x2c,
+       M_CAN_ECR       = 0x40,
+       M_CAN_PSR       = 0x44,
+       M_CAN_IR        = 0x50,
+       M_CAN_IE        = 0x54,
+       M_CAN_ILS       = 0x58,
+       M_CAN_ILE       = 0x5c,
+       M_CAN_GFC       = 0x80,
+       M_CAN_SIDFC     = 0x84,
+       M_CAN_XIDFC     = 0x88,
+       M_CAN_XIDAM     = 0x90,
+       M_CAN_HPMS      = 0x94,
+       M_CAN_NDAT1     = 0x98,
+       M_CAN_NDAT2     = 0x9c,
+       M_CAN_RXF0C     = 0xa0,
+       M_CAN_RXF0S     = 0xa4,
+       M_CAN_RXF0A     = 0xa8,
+       M_CAN_RXBC      = 0xac,
+       M_CAN_RXF1C     = 0xb0,
+       M_CAN_RXF1S     = 0xb4,
+       M_CAN_RXF1A     = 0xb8,
+       M_CAN_RXESC     = 0xbc,
+       M_CAN_TXBC      = 0xc0,
+       M_CAN_TXFQS     = 0xc4,
+       M_CAN_TXESC     = 0xc8,
+       M_CAN_TXBRP     = 0xcc,
+       M_CAN_TXBAR     = 0xd0,
+       M_CAN_TXBCR     = 0xd4,
+       M_CAN_TXBTO     = 0xd8,
+       M_CAN_TXBCF     = 0xdc,
+       M_CAN_TXBTIE    = 0xe0,
+       M_CAN_TXBCIE    = 0xe4,
+       M_CAN_TXEFC     = 0xf0,
+       M_CAN_TXEFS     = 0xf4,
+       M_CAN_TXEFA     = 0xf8,
+};
+
+/* m_can lec values */
+enum m_can_lec_type {
+       LEC_NO_ERROR = 0,
+       LEC_STUFF_ERROR,
+       LEC_FORM_ERROR,
+       LEC_ACK_ERROR,
+       LEC_BIT1_ERROR,
+       LEC_BIT0_ERROR,
+       LEC_CRC_ERROR,
+       LEC_UNUSED,
+};
+
+enum m_can_mram_cfg {
+       MRAM_SIDF = 0,
+       MRAM_XIDF,
+       MRAM_RXF0,
+       MRAM_RXF1,
+       MRAM_RXB,
+       MRAM_TXE,
+       MRAM_TXB,
+       MRAM_CFG_NUM,
+};
+
+/* Test Register (TEST) */
+#define TEST_LBCK      BIT(4)
+
+/* CC Control Register(CCCR) */
+#define CCCR_TEST      BIT(7)
+#define CCCR_MON       BIT(5)
+#define CCCR_CCE       BIT(1)
+#define CCCR_INIT      BIT(0)
+
+/* Bit Timing & Prescaler Register (BTP) */
+#define BTR_BRP_MASK           0x3ff
+#define BTR_BRP_SHIFT          16
+#define BTR_TSEG1_SHIFT                8
+#define BTR_TSEG1_MASK         (0x3f << BTR_TSEG1_SHIFT)
+#define BTR_TSEG2_SHIFT                4
+#define BTR_TSEG2_MASK         (0xf << BTR_TSEG2_SHIFT)
+#define BTR_SJW_SHIFT          0
+#define BTR_SJW_MASK           0xf
+
+/* Error Counter Register(ECR) */
+#define ECR_RP                 BIT(15)
+#define ECR_REC_SHIFT          8
+#define ECR_REC_MASK           (0x7f << ECR_REC_SHIFT)
+#define ECR_TEC_SHIFT          0
+#define ECR_TEC_MASK           0xff
+
+/* Protocol Status Register(PSR) */
+#define PSR_BO         BIT(7)
+#define PSR_EW         BIT(6)
+#define PSR_EP         BIT(5)
+#define PSR_LEC_MASK   0x7
+
+/* Interrupt Register(IR) */
+#define IR_ALL_INT     0xffffffff
+#define IR_STE         BIT(31)
+#define IR_FOE         BIT(30)
+#define IR_ACKE                BIT(29)
+#define IR_BE          BIT(28)
+#define IR_CRCE                BIT(27)
+#define IR_WDI         BIT(26)
+#define IR_BO          BIT(25)
+#define IR_EW          BIT(24)
+#define IR_EP          BIT(23)
+#define IR_ELO         BIT(22)
+#define IR_BEU         BIT(21)
+#define IR_BEC         BIT(20)
+#define IR_DRX         BIT(19)
+#define IR_TOO         BIT(18)
+#define IR_MRAF                BIT(17)
+#define IR_TSW         BIT(16)
+#define IR_TEFL                BIT(15)
+#define IR_TEFF                BIT(14)
+#define IR_TEFW                BIT(13)
+#define IR_TEFN                BIT(12)
+#define IR_TFE         BIT(11)
+#define IR_TCF         BIT(10)
+#define IR_TC          BIT(9)
+#define IR_HPM         BIT(8)
+#define IR_RF1L                BIT(7)
+#define IR_RF1F                BIT(6)
+#define IR_RF1W                BIT(5)
+#define IR_RF1N                BIT(4)
+#define IR_RF0L                BIT(3)
+#define IR_RF0F                BIT(2)
+#define IR_RF0W                BIT(1)
+#define IR_RF0N                BIT(0)
+#define IR_ERR_STATE   (IR_BO | IR_EW | IR_EP)
+#define IR_ERR_LEC     (IR_STE | IR_FOE | IR_ACKE | IR_BE | IR_CRCE)
+#define IR_ERR_BUS     (IR_ERR_LEC | IR_WDI | IR_ELO | IR_BEU | \
+                        IR_BEC | IR_TOO | IR_MRAF | IR_TSW | IR_TEFL | \
+                        IR_RF1L | IR_RF0L)
+#define IR_ERR_ALL     (IR_ERR_STATE | IR_ERR_BUS)
+
+/* Interrupt Line Select (ILS) */
+#define ILS_ALL_INT0   0x0
+#define ILS_ALL_INT1   0xFFFFFFFF
+
+/* Interrupt Line Enable (ILE) */
+#define ILE_EINT0      BIT(0)
+#define ILE_EINT1      BIT(1)
+
+/* Rx FIFO 0/1 Configuration (RXF0C/RXF1C) */
+#define RXFC_FWM_OFF   24
+#define RXFC_FWM_MASK  0x7f
+#define RXFC_FWM_1     (1 << RXFC_FWM_OFF)
+#define RXFC_FS_OFF    16
+#define RXFC_FS_MASK   0x7f
+
+/* Rx FIFO 0/1 Status (RXF0S/RXF1S) */
+#define RXFS_RFL       BIT(25)
+#define RXFS_FF                BIT(24)
+#define RXFS_FPI_OFF   16
+#define RXFS_FPI_MASK  0x3f0000
+#define RXFS_FGI_OFF   8
+#define RXFS_FGI_MASK  0x3f00
+#define RXFS_FFL_MASK  0x7f
+
+/* Rx Buffer / FIFO Element Size Configuration (RXESC) */
+#define M_CAN_RXESC_8BYTES     0x0
+
+/* Tx Buffer Configuration(TXBC) */
+#define TXBC_NDTB_OFF          16
+#define TXBC_NDTB_MASK         0x3f
+
+/* Tx Buffer Element Size Configuration(TXESC) */
+#define TXESC_TBDS_8BYTES      0x0
+
+/* Tx Event FIFO Con.guration (TXEFC) */
+#define TXEFC_EFS_OFF          16
+#define TXEFC_EFS_MASK         0x3f
+
+/* Message RAM Configuration (in bytes) */
+#define SIDF_ELEMENT_SIZE      4
+#define XIDF_ELEMENT_SIZE      8
+#define RXF0_ELEMENT_SIZE      16
+#define RXF1_ELEMENT_SIZE      16
+#define RXB_ELEMENT_SIZE       16
+#define TXE_ELEMENT_SIZE       8
+#define TXB_ELEMENT_SIZE       16
+
+/* Message RAM Elements */
+#define M_CAN_FIFO_ID          0x0
+#define M_CAN_FIFO_DLC         0x4
+#define M_CAN_FIFO_DATA(n)     (0x8 + ((n) << 2))
+
+/* Rx Buffer Element */
+#define RX_BUF_ESI             BIT(31)
+#define RX_BUF_XTD             BIT(30)
+#define RX_BUF_RTR             BIT(29)
+
+/* Tx Buffer Element */
+#define TX_BUF_XTD             BIT(30)
+#define TX_BUF_RTR             BIT(29)
+
+/* address offset and element number for each FIFO/Buffer in the Message RAM */
+struct mram_cfg {
+       u16 off;
+       u8  num;
+};
+
+/* m_can private data structure */
+struct m_can_priv {
+       struct can_priv can;    /* must be the first member */
+       struct napi_struct napi;
+       struct net_device *dev;
+       struct device *device;
+       struct clk *hclk;
+       struct clk *cclk;
+       void __iomem *base;
+       u32 irqstatus;
+
+       /* message ram configuration */
+       void __iomem *mram_base;
+       struct mram_cfg mcfg[MRAM_CFG_NUM];
+};
+
+static inline u32 m_can_read(const struct m_can_priv *priv, enum m_can_reg reg)
+{
+       return readl(priv->base + reg);
+}
+
+static inline void m_can_write(const struct m_can_priv *priv,
+                              enum m_can_reg reg, u32 val)
+{
+       writel(val, priv->base + reg);
+}
+
+static inline u32 m_can_fifo_read(const struct m_can_priv *priv,
+                                 u32 fgi, unsigned int offset)
+{
+       return readl(priv->mram_base + priv->mcfg[MRAM_RXF0].off +
+                    fgi * RXF0_ELEMENT_SIZE + offset);
+}
+
+static inline void m_can_fifo_write(const struct m_can_priv *priv,
+                                   u32 fpi, unsigned int offset, u32 val)
+{
+       return writel(val, priv->mram_base + priv->mcfg[MRAM_TXB].off +
+                     fpi * TXB_ELEMENT_SIZE + offset);
+}
+
+static inline void m_can_config_endisable(const struct m_can_priv *priv,
+                                         bool enable)
+{
+       u32 cccr = m_can_read(priv, M_CAN_CCCR);
+       u32 timeout = 10;
+       u32 val = 0;
+
+       if (enable) {
+               /* enable m_can configuration */
+               m_can_write(priv, M_CAN_CCCR, cccr | CCCR_INIT);
+               /* CCCR.CCE can only be set/reset while CCCR.INIT = '1' */
+               m_can_write(priv, M_CAN_CCCR, cccr | CCCR_INIT | CCCR_CCE);
+       } else {
+               m_can_write(priv, M_CAN_CCCR, cccr & ~(CCCR_INIT | CCCR_CCE));
+       }
+
+       /* there's a delay for module initialization */
+       if (enable)
+               val = CCCR_INIT | CCCR_CCE;
+
+       while ((m_can_read(priv, M_CAN_CCCR) & (CCCR_INIT | CCCR_CCE)) != val) {
+               if (timeout == 0) {
+                       netdev_warn(priv->dev, "Failed to init module\n");
+                       return;
+               }
+               timeout--;
+               udelay(1);
+       }
+}
+
+static inline void m_can_enable_all_interrupts(const struct m_can_priv *priv)
+{
+       m_can_write(priv, M_CAN_ILE, ILE_EINT0 | ILE_EINT1);
+}
+
+static inline void m_can_disable_all_interrupts(const struct m_can_priv *priv)
+{
+       m_can_write(priv, M_CAN_ILE, 0x0);
+}
+
+static void m_can_read_fifo(const struct net_device *dev, struct can_frame *cf,
+                           u32 rxfs)
+{
+       struct m_can_priv *priv = netdev_priv(dev);
+       u32 id, fgi;
+
+       /* calculate the fifo get index for where to read data */
+       fgi = (rxfs & RXFS_FGI_MASK) >> RXFS_FGI_OFF;
+       id = m_can_fifo_read(priv, fgi, M_CAN_FIFO_ID);
+       if (id & RX_BUF_XTD)
+               cf->can_id = (id & CAN_EFF_MASK) | CAN_EFF_FLAG;
+       else
+               cf->can_id = (id >> 18) & CAN_SFF_MASK;
+
+       if (id & RX_BUF_RTR) {
+               cf->can_id |= CAN_RTR_FLAG;
+       } else {
+               id = m_can_fifo_read(priv, fgi, M_CAN_FIFO_DLC);
+               cf->can_dlc = get_can_dlc((id >> 16) & 0x0F);
+               *(u32 *)(cf->data + 0) = m_can_fifo_read(priv, fgi,
+                                                        M_CAN_FIFO_DATA(0));
+               *(u32 *)(cf->data + 4) = m_can_fifo_read(priv, fgi,
+                                                        M_CAN_FIFO_DATA(1));
+       }
+
+       /* acknowledge rx fifo 0 */
+       m_can_write(priv, M_CAN_RXF0A, fgi);
+}
+
+static int m_can_do_rx_poll(struct net_device *dev, int quota)
+{
+       struct m_can_priv *priv = netdev_priv(dev);
+       struct net_device_stats *stats = &dev->stats;
+       struct sk_buff *skb;
+       struct can_frame *frame;
+       u32 pkts = 0;
+       u32 rxfs;
+
+       rxfs = m_can_read(priv, M_CAN_RXF0S);
+       if (!(rxfs & RXFS_FFL_MASK)) {
+               netdev_dbg(dev, "no messages in fifo0\n");
+               return 0;
+       }
+
+       while ((rxfs & RXFS_FFL_MASK) && (quota > 0)) {
+               if (rxfs & RXFS_RFL)
+                       netdev_warn(dev, "Rx FIFO 0 Message Lost\n");
+
+               skb = alloc_can_skb(dev, &frame);
+               if (!skb) {
+                       stats->rx_dropped++;
+                       return pkts;
+               }
+
+               m_can_read_fifo(dev, frame, rxfs);
+
+               stats->rx_packets++;
+               stats->rx_bytes += frame->can_dlc;
+
+               netif_receive_skb(skb);
+
+               quota--;
+               pkts++;
+               rxfs = m_can_read(priv, M_CAN_RXF0S);
+       }
+
+       if (pkts)
+               can_led_event(dev, CAN_LED_EVENT_RX);
+
+       return pkts;
+}
+
+static int m_can_handle_lost_msg(struct net_device *dev)
+{
+       struct net_device_stats *stats = &dev->stats;
+       struct sk_buff *skb;
+       struct can_frame *frame;
+
+       netdev_err(dev, "msg lost in rxf0\n");
+
+       stats->rx_errors++;
+       stats->rx_over_errors++;
+
+       skb = alloc_can_err_skb(dev, &frame);
+       if (unlikely(!skb))
+               return 0;
+
+       frame->can_id |= CAN_ERR_CRTL;
+       frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
+
+       netif_receive_skb(skb);
+
+       return 1;
+}
+
+static int m_can_handle_lec_err(struct net_device *dev,
+                               enum m_can_lec_type lec_type)
+{
+       struct m_can_priv *priv = netdev_priv(dev);
+       struct net_device_stats *stats = &dev->stats;
+       struct can_frame *cf;
+       struct sk_buff *skb;
+
+       priv->can.can_stats.bus_error++;
+       stats->rx_errors++;
+
+       /* propagate the error condition to the CAN stack */
+       skb = alloc_can_err_skb(dev, &cf);
+       if (unlikely(!skb))
+               return 0;
+
+       /* check for 'last error code' which tells us the
+        * type of the last error to occur on the CAN bus
+        */
+       cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
+       cf->data[2] |= CAN_ERR_PROT_UNSPEC;
+
+       switch (lec_type) {
+       case LEC_STUFF_ERROR:
+               netdev_dbg(dev, "stuff error\n");
+               cf->data[2] |= CAN_ERR_PROT_STUFF;
+               break;
+       case LEC_FORM_ERROR:
+               netdev_dbg(dev, "form error\n");
+               cf->data[2] |= CAN_ERR_PROT_FORM;
+               break;
+       case LEC_ACK_ERROR:
+               netdev_dbg(dev, "ack error\n");
+               cf->data[3] |= (CAN_ERR_PROT_LOC_ACK |
+                               CAN_ERR_PROT_LOC_ACK_DEL);
+               break;
+       case LEC_BIT1_ERROR:
+               netdev_dbg(dev, "bit1 error\n");
+               cf->data[2] |= CAN_ERR_PROT_BIT1;
+               break;
+       case LEC_BIT0_ERROR:
+               netdev_dbg(dev, "bit0 error\n");
+               cf->data[2] |= CAN_ERR_PROT_BIT0;
+               break;
+       case LEC_CRC_ERROR:
+               netdev_dbg(dev, "CRC error\n");
+               cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
+                               CAN_ERR_PROT_LOC_CRC_DEL);
+               break;
+       default:
+               break;
+       }
+
+       stats->rx_packets++;
+       stats->rx_bytes += cf->can_dlc;
+       netif_receive_skb(skb);
+
+       return 1;
+}
+
+static int m_can_get_berr_counter(const struct net_device *dev,
+                                 struct can_berr_counter *bec)
+{
+       struct m_can_priv *priv = netdev_priv(dev);
+       unsigned int ecr;
+       int err;
+
+       err = clk_prepare_enable(priv->hclk);
+       if (err)
+               return err;
+
+       err = clk_prepare_enable(priv->cclk);
+       if (err) {
+               clk_disable_unprepare(priv->hclk);
+               return err;
+       }
+
+       ecr = m_can_read(priv, M_CAN_ECR);
+       bec->rxerr = (ecr & ECR_REC_MASK) >> ECR_REC_SHIFT;
+       bec->txerr = ecr & ECR_TEC_MASK;
+
+       clk_disable_unprepare(priv->cclk);
+       clk_disable_unprepare(priv->hclk);
+
+       return 0;
+}
+
+static int m_can_handle_state_change(struct net_device *dev,
+                                    enum can_state new_state)
+{
+       struct m_can_priv *priv = netdev_priv(dev);
+       struct net_device_stats *stats = &dev->stats;
+       struct can_frame *cf;
+       struct sk_buff *skb;
+       struct can_berr_counter bec;
+       unsigned int ecr;
+
+       switch (new_state) {
+       case CAN_STATE_ERROR_ACTIVE:
+               /* error warning state */
+               priv->can.can_stats.error_warning++;
+               priv->can.state = CAN_STATE_ERROR_WARNING;
+               break;
+       case CAN_STATE_ERROR_PASSIVE:
+               /* error passive state */
+               priv->can.can_stats.error_passive++;
+               priv->can.state = CAN_STATE_ERROR_PASSIVE;
+               break;
+       case CAN_STATE_BUS_OFF:
+               /* bus-off state */
+               priv->can.state = CAN_STATE_BUS_OFF;
+               m_can_disable_all_interrupts(priv);
+               can_bus_off(dev);
+               break;
+       default:
+               break;
+       }
+
+       /* propagate the error condition to the CAN stack */
+       skb = alloc_can_err_skb(dev, &cf);
+       if (unlikely(!skb))
+               return 0;
+
+       m_can_get_berr_counter(dev, &bec);
+
+       switch (new_state) {
+       case CAN_STATE_ERROR_ACTIVE:
+               /* error warning state */
+               cf->can_id |= CAN_ERR_CRTL;
+               cf->data[1] = (bec.txerr > bec.rxerr) ?
+                       CAN_ERR_CRTL_TX_WARNING :
+                       CAN_ERR_CRTL_RX_WARNING;
+               cf->data[6] = bec.txerr;
+               cf->data[7] = bec.rxerr;
+               break;
+       case CAN_STATE_ERROR_PASSIVE:
+               /* error passive state */
+               cf->can_id |= CAN_ERR_CRTL;
+               ecr = m_can_read(priv, M_CAN_ECR);
+               if (ecr & ECR_RP)
+                       cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
+               if (bec.txerr > 127)
+                       cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
+               cf->data[6] = bec.txerr;
+               cf->data[7] = bec.rxerr;
+               break;
+       case CAN_STATE_BUS_OFF:
+               /* bus-off state */
+               cf->can_id |= CAN_ERR_BUSOFF;
+               break;
+       default:
+               break;
+       }
+
+       stats->rx_packets++;
+       stats->rx_bytes += cf->can_dlc;
+       netif_receive_skb(skb);
+
+       return 1;
+}
+
+static int m_can_handle_state_errors(struct net_device *dev, u32 psr)
+{
+       struct m_can_priv *priv = netdev_priv(dev);
+       int work_done = 0;
+
+       if ((psr & PSR_EW) &&
+           (priv->can.state != CAN_STATE_ERROR_WARNING)) {
+               netdev_dbg(dev, "entered error warning state\n");
+               work_done += m_can_handle_state_change(dev,
+                                                      CAN_STATE_ERROR_WARNING);
+       }
+
+       if ((psr & PSR_EP) &&
+           (priv->can.state != CAN_STATE_ERROR_PASSIVE)) {
+               netdev_dbg(dev, "entered error warning state\n");
+               work_done += m_can_handle_state_change(dev,
+                                                      CAN_STATE_ERROR_PASSIVE);
+       }
+
+       if ((psr & PSR_BO) &&
+           (priv->can.state != CAN_STATE_BUS_OFF)) {
+               netdev_dbg(dev, "entered error warning state\n");
+               work_done += m_can_handle_state_change(dev,
+                                                      CAN_STATE_BUS_OFF);
+       }
+
+       return work_done;
+}
+
+static void m_can_handle_other_err(struct net_device *dev, u32 irqstatus)
+{
+       if (irqstatus & IR_WDI)
+               netdev_err(dev, "Message RAM Watchdog event due to missing READY\n");
+       if (irqstatus & IR_BEU)
+               netdev_err(dev, "Error Logging Overflow\n");
+       if (irqstatus & IR_BEU)
+               netdev_err(dev, "Bit Error Uncorrected\n");
+       if (irqstatus & IR_BEC)
+               netdev_err(dev, "Bit Error Corrected\n");
+       if (irqstatus & IR_TOO)
+               netdev_err(dev, "Timeout reached\n");
+       if (irqstatus & IR_MRAF)
+               netdev_err(dev, "Message RAM access failure occurred\n");
+}
+
+static inline bool is_lec_err(u32 psr)
+{
+       psr &= LEC_UNUSED;
+
+       return psr && (psr != LEC_UNUSED);
+}
+
+static int m_can_handle_bus_errors(struct net_device *dev, u32 irqstatus,
+                                  u32 psr)
+{
+       struct m_can_priv *priv = netdev_priv(dev);
+       int work_done = 0;
+
+       if (irqstatus & IR_RF0L)
+               work_done += m_can_handle_lost_msg(dev);
+
+       /* handle lec errors on the bus */
+       if ((priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) &&
+           is_lec_err(psr))
+               work_done += m_can_handle_lec_err(dev, psr & LEC_UNUSED);
+
+       /* other unproccessed error interrupts */
+       m_can_handle_other_err(dev, irqstatus);
+
+       return work_done;
+}
+
+static int m_can_poll(struct napi_struct *napi, int quota)
+{
+       struct net_device *dev = napi->dev;
+       struct m_can_priv *priv = netdev_priv(dev);
+       int work_done = 0;
+       u32 irqstatus, psr;
+
+       irqstatus = priv->irqstatus | m_can_read(priv, M_CAN_IR);
+       if (!irqstatus)
+               goto end;
+
+       psr = m_can_read(priv, M_CAN_PSR);
+       if (irqstatus & IR_ERR_STATE)
+               work_done += m_can_handle_state_errors(dev, psr);
+
+       if (irqstatus & IR_ERR_BUS)
+               work_done += m_can_handle_bus_errors(dev, irqstatus, psr);
+
+       if (irqstatus & IR_RF0N)
+               work_done += m_can_do_rx_poll(dev, (quota - work_done));
+
+       if (work_done < quota) {
+               napi_complete(napi);
+               m_can_enable_all_interrupts(priv);
+       }
+
+end:
+       return work_done;
+}
+
+static irqreturn_t m_can_isr(int irq, void *dev_id)
+{
+       struct net_device *dev = (struct net_device *)dev_id;
+       struct m_can_priv *priv = netdev_priv(dev);
+       struct net_device_stats *stats = &dev->stats;
+       u32 ir;
+
+       ir = m_can_read(priv, M_CAN_IR);
+       if (!ir)
+               return IRQ_NONE;
+
+       /* ACK all irqs */
+       if (ir & IR_ALL_INT)
+               m_can_write(priv, M_CAN_IR, ir);
+
+       /* schedule NAPI in case of
+        * - rx IRQ
+        * - state change IRQ
+        * - bus error IRQ and bus error reporting
+        */
+       if ((ir & IR_RF0N) || (ir & IR_ERR_ALL)) {
+               priv->irqstatus = ir;
+               m_can_disable_all_interrupts(priv);
+               napi_schedule(&priv->napi);
+       }
+
+       /* transmission complete interrupt */
+       if (ir & IR_TC) {
+               stats->tx_bytes += can_get_echo_skb(dev, 0);
+               stats->tx_packets++;
+               can_led_event(dev, CAN_LED_EVENT_TX);
+               netif_wake_queue(dev);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static const struct can_bittiming_const m_can_bittiming_const = {
+       .name = KBUILD_MODNAME,
+       .tseg1_min = 2,         /* Time segment 1 = prop_seg + phase_seg1 */
+       .tseg1_max = 64,
+       .tseg2_min = 1,         /* Time segment 2 = phase_seg2 */
+       .tseg2_max = 16,
+       .sjw_max = 16,
+       .brp_min = 1,
+       .brp_max = 1024,
+       .brp_inc = 1,
+};
+
+static int m_can_set_bittiming(struct net_device *dev)
+{
+       struct m_can_priv *priv = netdev_priv(dev);
+       const struct can_bittiming *bt = &priv->can.bittiming;
+       u16 brp, sjw, tseg1, tseg2;
+       u32 reg_btp;
+
+       brp = bt->brp - 1;
+       sjw = bt->sjw - 1;
+       tseg1 = bt->prop_seg + bt->phase_seg1 - 1;
+       tseg2 = bt->phase_seg2 - 1;
+       reg_btp = (brp << BTR_BRP_SHIFT) | (sjw << BTR_SJW_SHIFT) |
+                       (tseg1 << BTR_TSEG1_SHIFT) | (tseg2 << BTR_TSEG2_SHIFT);
+       m_can_write(priv, M_CAN_BTP, reg_btp);
+       netdev_dbg(dev, "setting BTP 0x%x\n", reg_btp);
+
+       return 0;
+}
+
+/* Configure M_CAN chip:
+ * - set rx buffer/fifo element size
+ * - configure rx fifo
+ * - accept non-matching frame into fifo 0
+ * - configure tx buffer
+ * - configure mode
+ * - setup bittiming
+ */
+static void m_can_chip_config(struct net_device *dev)
+{
+       struct m_can_priv *priv = netdev_priv(dev);
+       u32 cccr, test;
+
+       m_can_config_endisable(priv, true);
+
+       /* RX Buffer/FIFO Element Size 8 bytes data field */
+       m_can_write(priv, M_CAN_RXESC, M_CAN_RXESC_8BYTES);
+
+       /* Accept Non-matching Frames Into FIFO 0 */
+       m_can_write(priv, M_CAN_GFC, 0x0);
+
+       /* only support one Tx Buffer currently */
+       m_can_write(priv, M_CAN_TXBC, (1 << TXBC_NDTB_OFF) |
+                   priv->mcfg[MRAM_TXB].off);
+
+       /* only support 8 bytes firstly */
+       m_can_write(priv, M_CAN_TXESC, TXESC_TBDS_8BYTES);
+
+       m_can_write(priv, M_CAN_TXEFC, (1 << TXEFC_EFS_OFF) |
+                   priv->mcfg[MRAM_TXE].off);
+
+       /* rx fifo configuration, blocking mode, fifo size 1 */
+       m_can_write(priv, M_CAN_RXF0C,
+                   (priv->mcfg[MRAM_RXF0].num << RXFC_FS_OFF) |
+                   RXFC_FWM_1 | priv->mcfg[MRAM_RXF0].off);
+
+       m_can_write(priv, M_CAN_RXF1C,
+                   (priv->mcfg[MRAM_RXF1].num << RXFC_FS_OFF) |
+                   RXFC_FWM_1 | priv->mcfg[MRAM_RXF1].off);
+
+       cccr = m_can_read(priv, M_CAN_CCCR);
+       cccr &= ~(CCCR_TEST | CCCR_MON);
+       test = m_can_read(priv, M_CAN_TEST);
+       test &= ~TEST_LBCK;
+
+       if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
+               cccr |= CCCR_MON;
+
+       if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) {
+               cccr |= CCCR_TEST;
+               test |= TEST_LBCK;
+       }
+
+       m_can_write(priv, M_CAN_CCCR, cccr);
+       m_can_write(priv, M_CAN_TEST, test);
+
+       /* enable interrupts */
+       m_can_write(priv, M_CAN_IR, IR_ALL_INT);
+       if (!(priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING))
+               m_can_write(priv, M_CAN_IE, IR_ALL_INT & ~IR_ERR_LEC);
+       else
+               m_can_write(priv, M_CAN_IE, IR_ALL_INT);
+
+       /* route all interrupts to INT0 */
+       m_can_write(priv, M_CAN_ILS, ILS_ALL_INT0);
+
+       /* set bittiming params */
+       m_can_set_bittiming(dev);
+
+       m_can_config_endisable(priv, false);
+}
+
+static void m_can_start(struct net_device *dev)
+{
+       struct m_can_priv *priv = netdev_priv(dev);
+
+       /* basic m_can configuration */
+       m_can_chip_config(dev);
+
+       priv->can.state = CAN_STATE_ERROR_ACTIVE;
+
+       m_can_enable_all_interrupts(priv);
+}
+
+static int m_can_set_mode(struct net_device *dev, enum can_mode mode)
+{
+       switch (mode) {
+       case CAN_MODE_START:
+               m_can_start(dev);
+               netif_wake_queue(dev);
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
+static void free_m_can_dev(struct net_device *dev)
+{
+       free_candev(dev);
+}
+
+static struct net_device *alloc_m_can_dev(void)
+{
+       struct net_device *dev;
+       struct m_can_priv *priv;
+
+       dev = alloc_candev(sizeof(*priv), 1);
+       if (!dev)
+               return NULL;
+
+       priv = netdev_priv(dev);
+       netif_napi_add(dev, &priv->napi, m_can_poll, M_CAN_NAPI_WEIGHT);
+
+       priv->dev = dev;
+       priv->can.bittiming_const = &m_can_bittiming_const;
+       priv->can.do_set_mode = m_can_set_mode;
+       priv->can.do_get_berr_counter = m_can_get_berr_counter;
+       priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
+                                       CAN_CTRLMODE_LISTENONLY |
+                                       CAN_CTRLMODE_BERR_REPORTING;
+
+       return dev;
+}
+
+static int m_can_open(struct net_device *dev)
+{
+       struct m_can_priv *priv = netdev_priv(dev);
+       int err;
+
+       err = clk_prepare_enable(priv->hclk);
+       if (err)
+               return err;
+
+       err = clk_prepare_enable(priv->cclk);
+       if (err)
+               goto exit_disable_hclk;
+
+       /* open the can device */
+       err = open_candev(dev);
+       if (err) {
+               netdev_err(dev, "failed to open can device\n");
+               goto exit_disable_cclk;
+       }
+
+       /* register interrupt handler */
+       err = request_irq(dev->irq, m_can_isr, IRQF_SHARED, dev->name,
+                         dev);
+       if (err < 0) {
+               netdev_err(dev, "failed to request interrupt\n");
+               goto exit_irq_fail;
+       }
+
+       /* start the m_can controller */
+       m_can_start(dev);
+
+       can_led_event(dev, CAN_LED_EVENT_OPEN);
+       napi_enable(&priv->napi);
+       netif_start_queue(dev);
+
+       return 0;
+
+exit_irq_fail:
+       close_candev(dev);
+exit_disable_cclk:
+       clk_disable_unprepare(priv->cclk);
+exit_disable_hclk:
+       clk_disable_unprepare(priv->hclk);
+       return err;
+}
+
+static void m_can_stop(struct net_device *dev)
+{
+       struct m_can_priv *priv = netdev_priv(dev);
+
+       /* disable all interrupts */
+       m_can_disable_all_interrupts(priv);
+
+       clk_disable_unprepare(priv->hclk);
+       clk_disable_unprepare(priv->cclk);
+
+       /* set the state as STOPPED */
+       priv->can.state = CAN_STATE_STOPPED;
+}
+
+static int m_can_close(struct net_device *dev)
+{
+       struct m_can_priv *priv = netdev_priv(dev);
+
+       netif_stop_queue(dev);
+       napi_disable(&priv->napi);
+       m_can_stop(dev);
+       free_irq(dev->irq, dev);
+       close_candev(dev);
+       can_led_event(dev, CAN_LED_EVENT_STOP);
+
+       return 0;
+}
+
+static netdev_tx_t m_can_start_xmit(struct sk_buff *skb,
+                                   struct net_device *dev)
+{
+       struct m_can_priv *priv = netdev_priv(dev);
+       struct can_frame *cf = (struct can_frame *)skb->data;
+       u32 id;
+
+       if (can_dropped_invalid_skb(dev, skb))
+               return NETDEV_TX_OK;
+
+       netif_stop_queue(dev);
+
+       if (cf->can_id & CAN_EFF_FLAG) {
+               id = cf->can_id & CAN_EFF_MASK;
+               id |= TX_BUF_XTD;
+       } else {
+               id = ((cf->can_id & CAN_SFF_MASK) << 18);
+       }
+
+       if (cf->can_id & CAN_RTR_FLAG)
+               id |= TX_BUF_RTR;
+
+       /* message ram configuration */
+       m_can_fifo_write(priv, 0, M_CAN_FIFO_ID, id);
+       m_can_fifo_write(priv, 0, M_CAN_FIFO_DLC, cf->can_dlc << 16);
+       m_can_fifo_write(priv, 0, M_CAN_FIFO_DATA(0), *(u32 *)(cf->data + 0));
+       m_can_fifo_write(priv, 0, M_CAN_FIFO_DATA(1), *(u32 *)(cf->data + 4));
+       can_put_echo_skb(skb, dev, 0);
+
+       /* enable first TX buffer to start transfer  */
+       m_can_write(priv, M_CAN_TXBTIE, 0x1);
+       m_can_write(priv, M_CAN_TXBAR, 0x1);
+
+       return NETDEV_TX_OK;
+}
+
+static const struct net_device_ops m_can_netdev_ops = {
+       .ndo_open = m_can_open,
+       .ndo_stop = m_can_close,
+       .ndo_start_xmit = m_can_start_xmit,
+};
+
+static int register_m_can_dev(struct net_device *dev)
+{
+       dev->flags |= IFF_ECHO; /* we support local echo */
+       dev->netdev_ops = &m_can_netdev_ops;
+
+       return register_candev(dev);
+}
+
+static int m_can_of_parse_mram(struct platform_device *pdev,
+                              struct m_can_priv *priv)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct resource *res;
+       void __iomem *addr;
+       u32 out_val[MRAM_CFG_LEN];
+       int ret;
+
+       /* message ram could be shared */
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "message_ram");
+       if (!res)
+               return -ENODEV;
+
+       addr = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+       if (!addr)
+               return -ENOMEM;
+
+       /* get message ram configuration */
+       ret = of_property_read_u32_array(np, "bosch,mram-cfg",
+                                        out_val, sizeof(out_val) / 4);
+       if (ret) {
+               dev_err(&pdev->dev, "can not get message ram configuration\n");
+               return -ENODEV;
+       }
+
+       priv->mram_base = addr;
+       priv->mcfg[MRAM_SIDF].off = out_val[0];
+       priv->mcfg[MRAM_SIDF].num = out_val[1];
+       priv->mcfg[MRAM_XIDF].off = priv->mcfg[MRAM_SIDF].off +
+                       priv->mcfg[MRAM_SIDF].num * SIDF_ELEMENT_SIZE;
+       priv->mcfg[MRAM_XIDF].num = out_val[2];
+       priv->mcfg[MRAM_RXF0].off = priv->mcfg[MRAM_XIDF].off +
+                       priv->mcfg[MRAM_XIDF].num * XIDF_ELEMENT_SIZE;
+       priv->mcfg[MRAM_RXF0].num = out_val[3] & RXFC_FS_MASK;
+       priv->mcfg[MRAM_RXF1].off = priv->mcfg[MRAM_RXF0].off +
+                       priv->mcfg[MRAM_RXF0].num * RXF0_ELEMENT_SIZE;
+       priv->mcfg[MRAM_RXF1].num = out_val[4] & RXFC_FS_MASK;
+       priv->mcfg[MRAM_RXB].off = priv->mcfg[MRAM_RXF1].off +
+                       priv->mcfg[MRAM_RXF1].num * RXF1_ELEMENT_SIZE;
+       priv->mcfg[MRAM_RXB].num = out_val[5];
+       priv->mcfg[MRAM_TXE].off = priv->mcfg[MRAM_RXB].off +
+                       priv->mcfg[MRAM_RXB].num * RXB_ELEMENT_SIZE;
+       priv->mcfg[MRAM_TXE].num = out_val[6];
+       priv->mcfg[MRAM_TXB].off = priv->mcfg[MRAM_TXE].off +
+                       priv->mcfg[MRAM_TXE].num * TXE_ELEMENT_SIZE;
+       priv->mcfg[MRAM_TXB].num = out_val[7] & TXBC_NDTB_MASK;
+
+       dev_dbg(&pdev->dev, "mram_base %p sidf 0x%x %d xidf 0x%x %d rxf0 0x%x %d rxf1 0x%x %d rxb 0x%x %d txe 0x%x %d txb 0x%x %d\n",
+               priv->mram_base,
+               priv->mcfg[MRAM_SIDF].off, priv->mcfg[MRAM_SIDF].num,
+               priv->mcfg[MRAM_XIDF].off, priv->mcfg[MRAM_XIDF].num,
+               priv->mcfg[MRAM_RXF0].off, priv->mcfg[MRAM_RXF0].num,
+               priv->mcfg[MRAM_RXF1].off, priv->mcfg[MRAM_RXF1].num,
+               priv->mcfg[MRAM_RXB].off, priv->mcfg[MRAM_RXB].num,
+               priv->mcfg[MRAM_TXE].off, priv->mcfg[MRAM_TXE].num,
+               priv->mcfg[MRAM_TXB].off, priv->mcfg[MRAM_TXB].num);
+
+       return 0;
+}
+
+static int m_can_plat_probe(struct platform_device *pdev)
+{
+       struct net_device *dev;
+       struct m_can_priv *priv;
+       struct resource *res;
+       void __iomem *addr;
+       struct clk *hclk, *cclk;
+       int irq, ret;
+
+       hclk = devm_clk_get(&pdev->dev, "hclk");
+       cclk = devm_clk_get(&pdev->dev, "cclk");
+       if (IS_ERR(hclk) || IS_ERR(cclk)) {
+               dev_err(&pdev->dev, "no clock find\n");
+               return -ENODEV;
+       }
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "m_can");
+       addr = devm_ioremap_resource(&pdev->dev, res);
+       irq = platform_get_irq_byname(pdev, "int0");
+       if (IS_ERR(addr) || irq < 0)
+               return -EINVAL;
+
+       /* allocate the m_can device */
+       dev = alloc_m_can_dev();
+       if (!dev)
+               return -ENOMEM;
+
+       priv = netdev_priv(dev);
+       dev->irq = irq;
+       priv->base = addr;
+       priv->device = &pdev->dev;
+       priv->hclk = hclk;
+       priv->cclk = cclk;
+       priv->can.clock.freq = clk_get_rate(cclk);
+
+       ret = m_can_of_parse_mram(pdev, priv);
+       if (ret)
+               goto failed_free_dev;
+
+       platform_set_drvdata(pdev, dev);
+       SET_NETDEV_DEV(dev, &pdev->dev);
+
+       ret = register_m_can_dev(dev);
+       if (ret) {
+               dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
+                       KBUILD_MODNAME, ret);
+               goto failed_free_dev;
+       }
+
+       devm_can_led_init(dev);
+
+       dev_info(&pdev->dev, "%s device registered (regs=%p, irq=%d)\n",
+                KBUILD_MODNAME, priv->base, dev->irq);
+
+       return 0;
+
+failed_free_dev:
+       free_m_can_dev(dev);
+       return ret;
+}
+
+static __maybe_unused int m_can_suspend(struct device *dev)
+{
+       struct net_device *ndev = dev_get_drvdata(dev);
+       struct m_can_priv *priv = netdev_priv(ndev);
+
+       if (netif_running(ndev)) {
+               netif_stop_queue(ndev);
+               netif_device_detach(ndev);
+       }
+
+       /* TODO: enter low power */
+
+       priv->can.state = CAN_STATE_SLEEPING;
+
+       return 0;
+}
+
+static __maybe_unused int m_can_resume(struct device *dev)
+{
+       struct net_device *ndev = dev_get_drvdata(dev);
+       struct m_can_priv *priv = netdev_priv(ndev);
+
+       /* TODO: exit low power */
+
+       priv->can.state = CAN_STATE_ERROR_ACTIVE;
+
+       if (netif_running(ndev)) {
+               netif_device_attach(ndev);
+               netif_start_queue(ndev);
+       }
+
+       return 0;
+}
+
+static void unregister_m_can_dev(struct net_device *dev)
+{
+       unregister_candev(dev);
+}
+
+static int m_can_plat_remove(struct platform_device *pdev)
+{
+       struct net_device *dev = platform_get_drvdata(pdev);
+
+       unregister_m_can_dev(dev);
+       platform_set_drvdata(pdev, NULL);
+
+       free_m_can_dev(dev);
+
+       return 0;
+}
+
+static const struct dev_pm_ops m_can_pmops = {
+       SET_SYSTEM_SLEEP_PM_OPS(m_can_suspend, m_can_resume)
+};
+
+static const struct of_device_id m_can_of_table[] = {
+       { .compatible = "bosch,m_can", .data = NULL },
+       { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, m_can_of_table);
+
+static struct platform_driver m_can_plat_driver = {
+       .driver = {
+               .name = KBUILD_MODNAME,
+               .of_match_table = m_can_of_table,
+               .pm     = &m_can_pmops,
+       },
+       .probe = m_can_plat_probe,
+       .remove = m_can_plat_remove,
+};
+
+module_platform_driver(m_can_plat_driver);
+
+MODULE_AUTHOR("Dong Aisheng <b29396@freescale.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CAN bus driver for Bosch M_CAN controller");
index c9fab17cd8b4d9b37297b1a339faea8f7d820871..58903b45f5fb91c5649eb4c458a41034ab478eef 100644 (file)
@@ -1,5 +1,3 @@
 
 obj-$(CONFIG_CAN_MPC5XXX)      += mscan-mpc5xxx.o
 mscan-mpc5xxx-objs             := mscan.o mpc5xxx_can.o
-
-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
index 5268d216ecfae7b5a447abbd1327d7a08a632b46..1abe133d159428e0e098d611e8898bdaabb04c71 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/can/dev.h>
 #include <linux/clk.h>
 #include <linux/can/platform/rcar_can.h>
+#include <linux/of.h>
 
 #define RCAR_CAN_DRV_NAME      "rcar_can"
 
@@ -87,6 +88,7 @@ struct rcar_can_priv {
        struct napi_struct napi;
        struct rcar_can_regs __iomem *regs;
        struct clk *clk;
+       struct clk *can_clk;
        u8 tx_dlc[RCAR_CAN_FIFO_DEPTH];
        u32 tx_head;
        u32 tx_tail;
@@ -505,14 +507,20 @@ static int rcar_can_open(struct net_device *ndev)
 
        err = clk_prepare_enable(priv->clk);
        if (err) {
-               netdev_err(ndev, "clk_prepare_enable() failed, error %d\n",
+               netdev_err(ndev, "failed to enable periperal clock, error %d\n",
                           err);
                goto out;
        }
+       err = clk_prepare_enable(priv->can_clk);
+       if (err) {
+               netdev_err(ndev, "failed to enable CAN clock, error %d\n",
+                          err);
+               goto out_clock;
+       }
        err = open_candev(ndev);
        if (err) {
                netdev_err(ndev, "open_candev() failed, error %d\n", err);
-               goto out_clock;
+               goto out_can_clock;
        }
        napi_enable(&priv->napi);
        err = request_irq(ndev->irq, rcar_can_interrupt, 0, ndev->name, ndev);
@@ -527,6 +535,8 @@ static int rcar_can_open(struct net_device *ndev)
 out_close:
        napi_disable(&priv->napi);
        close_candev(ndev);
+out_can_clock:
+       clk_disable_unprepare(priv->can_clk);
 out_clock:
        clk_disable_unprepare(priv->clk);
 out:
@@ -565,6 +575,7 @@ static int rcar_can_close(struct net_device *ndev)
        rcar_can_stop(ndev);
        free_irq(ndev->irq, ndev);
        napi_disable(&priv->napi);
+       clk_disable_unprepare(priv->can_clk);
        clk_disable_unprepare(priv->clk);
        close_candev(ndev);
        can_led_event(ndev, CAN_LED_EVENT_STOP);
@@ -715,6 +726,12 @@ static int rcar_can_get_berr_counter(const struct net_device *dev,
        return 0;
 }
 
+static const char * const clock_names[] = {
+       [CLKR_CLKP1]    = "clkp1",
+       [CLKR_CLKP2]    = "clkp2",
+       [CLKR_CLKEXT]   = "can_clk",
+};
+
 static int rcar_can_probe(struct platform_device *pdev)
 {
        struct rcar_can_platform_data *pdata;
@@ -722,13 +739,20 @@ static int rcar_can_probe(struct platform_device *pdev)
        struct net_device *ndev;
        struct resource *mem;
        void __iomem *addr;
+       u32 clock_select = CLKR_CLKP1;
        int err = -ENODEV;
        int irq;
 
-       pdata = dev_get_platdata(&pdev->dev);
-       if (!pdata) {
-               dev_err(&pdev->dev, "No platform data provided!\n");
-               goto fail;
+       if (pdev->dev.of_node) {
+               of_property_read_u32(pdev->dev.of_node,
+                                    "renesas,can-clock-select", &clock_select);
+       } else {
+               pdata = dev_get_platdata(&pdev->dev);
+               if (!pdata) {
+                       dev_err(&pdev->dev, "No platform data provided!\n");
+                       goto fail;
+               }
+               clock_select = pdata->clock_select;
        }
 
        irq = platform_get_irq(pdev, 0);
@@ -753,10 +777,22 @@ static int rcar_can_probe(struct platform_device *pdev)
 
        priv = netdev_priv(ndev);
 
-       priv->clk = devm_clk_get(&pdev->dev, NULL);
+       priv->clk = devm_clk_get(&pdev->dev, "clkp1");
        if (IS_ERR(priv->clk)) {
                err = PTR_ERR(priv->clk);
-               dev_err(&pdev->dev, "cannot get clock: %d\n", err);
+               dev_err(&pdev->dev, "cannot get peripheral clock: %d\n", err);
+               goto fail_clk;
+       }
+
+       if (clock_select >= ARRAY_SIZE(clock_names)) {
+               err = -EINVAL;
+               dev_err(&pdev->dev, "invalid CAN clock selected\n");
+               goto fail_clk;
+       }
+       priv->can_clk = devm_clk_get(&pdev->dev, clock_names[clock_select]);
+       if (IS_ERR(priv->can_clk)) {
+               err = PTR_ERR(priv->can_clk);
+               dev_err(&pdev->dev, "cannot get CAN clock: %d\n", err);
                goto fail_clk;
        }
 
@@ -765,8 +801,8 @@ static int rcar_can_probe(struct platform_device *pdev)
        ndev->flags |= IFF_ECHO;
        priv->ndev = ndev;
        priv->regs = addr;
-       priv->clock_select = pdata->clock_select;
-       priv->can.clock.freq = clk_get_rate(priv->clk);
+       priv->clock_select = clock_select;
+       priv->can.clock.freq = clk_get_rate(priv->can_clk);
        priv->can.bittiming_const = &rcar_can_bittiming_const;
        priv->can.do_set_mode = rcar_can_do_set_mode;
        priv->can.do_get_berr_counter = rcar_can_get_berr_counter;
@@ -858,10 +894,20 @@ static int __maybe_unused rcar_can_resume(struct device *dev)
 
 static SIMPLE_DEV_PM_OPS(rcar_can_pm_ops, rcar_can_suspend, rcar_can_resume);
 
+static const struct of_device_id rcar_can_of_table[] __maybe_unused = {
+       { .compatible = "renesas,can-r8a7778" },
+       { .compatible = "renesas,can-r8a7779" },
+       { .compatible = "renesas,can-r8a7790" },
+       { .compatible = "renesas,can-r8a7791" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, rcar_can_of_table);
+
 static struct platform_driver rcar_can_driver = {
        .driver = {
                .name = RCAR_CAN_DRV_NAME,
                .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(rcar_can_of_table),
                .pm = &rcar_can_pm_ops,
        },
        .probe = rcar_can_probe,
index 531d5fcc97e58bded41ac3f3022a2a84a41ba6f0..be11ddd11b87447c8e2b348bdeb7b57cca1b5d25 100644 (file)
@@ -12,5 +12,3 @@ obj-$(CONFIG_CAN_PEAK_PCMCIA) += peak_pcmcia.o
 obj-$(CONFIG_CAN_PEAK_PCI) += peak_pci.o
 obj-$(CONFIG_CAN_PLX_PCI) += plx_pci.o
 obj-$(CONFIG_CAN_TSCAN1) += tscan1.o
-
-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
index d1692154ed1b094ab100bc40ddcc2783d1dfdac7..b27ac6074afb1d21ab63282298002f8a4992599b 100644 (file)
@@ -172,6 +172,35 @@ static void set_normal_mode(struct net_device *dev)
        netdev_err(dev, "setting SJA1000 into normal mode failed!\n");
 }
 
+/*
+ * initialize SJA1000 chip:
+ *   - reset chip
+ *   - set output mode
+ *   - set baudrate
+ *   - enable interrupts
+ *   - start operating mode
+ */
+static void chipset_init(struct net_device *dev)
+{
+       struct sja1000_priv *priv = netdev_priv(dev);
+
+       /* set clock divider and output control register */
+       priv->write_reg(priv, SJA1000_CDR, priv->cdr | CDR_PELICAN);
+
+       /* set acceptance filter (accept all) */
+       priv->write_reg(priv, SJA1000_ACCC0, 0x00);
+       priv->write_reg(priv, SJA1000_ACCC1, 0x00);
+       priv->write_reg(priv, SJA1000_ACCC2, 0x00);
+       priv->write_reg(priv, SJA1000_ACCC3, 0x00);
+
+       priv->write_reg(priv, SJA1000_ACCM0, 0xFF);
+       priv->write_reg(priv, SJA1000_ACCM1, 0xFF);
+       priv->write_reg(priv, SJA1000_ACCM2, 0xFF);
+       priv->write_reg(priv, SJA1000_ACCM3, 0xFF);
+
+       priv->write_reg(priv, SJA1000_OCR, priv->ocr | OCR_MODE_NORMAL);
+}
+
 static void sja1000_start(struct net_device *dev)
 {
        struct sja1000_priv *priv = netdev_priv(dev);
@@ -180,6 +209,10 @@ static void sja1000_start(struct net_device *dev)
        if (priv->can.state != CAN_STATE_STOPPED)
                set_reset_mode(dev);
 
+       /* Initialize chip if uninitialized at this stage */
+       if (!(priv->read_reg(priv, SJA1000_CDR) & CDR_PELICAN))
+               chipset_init(dev);
+
        /* Clear error counters and error code capture */
        priv->write_reg(priv, SJA1000_TXERR, 0x0);
        priv->write_reg(priv, SJA1000_RXERR, 0x0);
@@ -236,35 +269,6 @@ static int sja1000_get_berr_counter(const struct net_device *dev,
        return 0;
 }
 
-/*
- * initialize SJA1000 chip:
- *   - reset chip
- *   - set output mode
- *   - set baudrate
- *   - enable interrupts
- *   - start operating mode
- */
-static void chipset_init(struct net_device *dev)
-{
-       struct sja1000_priv *priv = netdev_priv(dev);
-
-       /* set clock divider and output control register */
-       priv->write_reg(priv, SJA1000_CDR, priv->cdr | CDR_PELICAN);
-
-       /* set acceptance filter (accept all) */
-       priv->write_reg(priv, SJA1000_ACCC0, 0x00);
-       priv->write_reg(priv, SJA1000_ACCC1, 0x00);
-       priv->write_reg(priv, SJA1000_ACCC2, 0x00);
-       priv->write_reg(priv, SJA1000_ACCC3, 0x00);
-
-       priv->write_reg(priv, SJA1000_ACCM0, 0xFF);
-       priv->write_reg(priv, SJA1000_ACCM1, 0xFF);
-       priv->write_reg(priv, SJA1000_ACCM2, 0xFF);
-       priv->write_reg(priv, SJA1000_ACCM3, 0xFF);
-
-       priv->write_reg(priv, SJA1000_OCR, priv->ocr | OCR_MODE_NORMAL);
-}
-
 /*
  * transmit a CAN message
  * message layout in the sk_buff should be like this:
index c5e5016c742ee040f5ccf8f202b4896357abe7b4..a23da492dad52b169bcdca64cc4fbb6d729d9979 100644 (file)
@@ -2,5 +2,3 @@
 softing-y := softing_main.o softing_fw.o
 obj-$(CONFIG_CAN_SOFTING) += softing.o
 obj-$(CONFIG_CAN_SOFTING_CS) += softing_cs.o
-
-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
index 90bcacffbc65c15372c32cb04df36b6781b82024..0e86040cdd8ce9c2ca037ed27c234dd362812a5f 100644 (file)
@@ -4,5 +4,3 @@
 
 
 obj-$(CONFIG_CAN_MCP251X)      += mcp251x.o
-
-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
index 5df239e68812635e1d209f835e9a62dbe2fdf555..c66d699640a9c1478026da5df023264a7b1ff973 100644 (file)
@@ -1107,10 +1107,10 @@ static int mcp251x_can_probe(struct spi_device *spi)
                 * Minimum coherent DMA allocation is PAGE_SIZE, so allocate
                 * that much and share it between Tx and Rx DMA buffers.
                 */
-               priv->spi_tx_buf = dma_alloc_coherent(&spi->dev,
-                                                     PAGE_SIZE,
-                                                     &priv->spi_tx_dma,
-                                                     GFP_DMA);
+               priv->spi_tx_buf = dmam_alloc_coherent(&spi->dev,
+                                                      PAGE_SIZE,
+                                                      &priv->spi_tx_dma,
+                                                      GFP_DMA);
 
                if (priv->spi_tx_buf) {
                        priv->spi_rx_buf = (priv->spi_tx_buf + (PAGE_SIZE / 2));
@@ -1156,9 +1156,6 @@ static int mcp251x_can_probe(struct spi_device *spi)
        return 0;
 
 error_probe:
-       if (mcp251x_enable_dma)
-               dma_free_coherent(&spi->dev, PAGE_SIZE,
-                                 priv->spi_tx_buf, priv->spi_tx_dma);
        mcp251x_power_enable(priv->power, 0);
 
 out_clk:
@@ -1178,11 +1175,6 @@ static int mcp251x_can_remove(struct spi_device *spi)
 
        unregister_candev(net);
 
-       if (mcp251x_enable_dma) {
-               dma_free_coherent(&spi->dev, PAGE_SIZE,
-                                 priv->spi_tx_buf, priv->spi_tx_dma);
-       }
-
        mcp251x_power_enable(priv->power, 0);
 
        if (!IS_ERR(priv->clk))
index 7b9a393b1ac82a1caf4684a704d7121ad16dc3c9..a64cf983fb87af3111c0b8b8ed276943a20067e4 100644 (file)
@@ -8,5 +8,3 @@ obj-$(CONFIG_CAN_GS_USB) += gs_usb.o
 obj-$(CONFIG_CAN_KVASER_USB) += kvaser_usb.o
 obj-$(CONFIG_CAN_PEAK_USB) += peak_usb/
 obj-$(CONFIG_CAN_8DEV_USB) += usb_8dev.o
-
-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
index b8fe808b7957c735e0f4c8248ad3bcff14b46716..c6ee07c6a1b54d3197d3ff04ee40f426d097b7de 100644 (file)
@@ -36,4 +36,15 @@ config NET_DSA_MV88E6123_61_65
          This enables support for the Marvell 88E6123/6161/6165
          ethernet switch chips.
 
+config NET_DSA_BCM_SF2
+       tristate "Broadcom Starfighter 2 Ethernet switch support"
+       select NET_DSA
+       select NET_DSA_TAG_BRCM
+       select FIXED_PHY if NET_DSA_BCM_SF2=y
+       select BCM7XXX_PHY
+       select MDIO_BCM_UNIMAC
+       ---help---
+         This enables support for the Broadcom Starfighter 2 Ethernet
+         switch chips.
+
 endmenu
index f3bda05536cc55e861ae2996103d930433a74dfc..dd3cd3b8157f82ead0a78c07fdf2d7c0754418bd 100644 (file)
@@ -7,3 +7,4 @@ endif
 ifdef CONFIG_NET_DSA_MV88E6131
 mv88e6xxx_drv-y += mv88e6131.o
 endif
+obj-$(CONFIG_NET_DSA_BCM_SF2)  += bcm_sf2.o
diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c
new file mode 100644 (file)
index 0000000..bb7cb8e
--- /dev/null
@@ -0,0 +1,626 @@
+/*
+ * Broadcom Starfighter 2 DSA switch 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/phy.h>
+#include <linux/phy_fixed.h>
+#include <linux/mii.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <net/dsa.h>
+
+#include "bcm_sf2.h"
+#include "bcm_sf2_regs.h"
+
+/* String, offset, and register size in bytes if different from 4 bytes */
+static const struct bcm_sf2_hw_stats bcm_sf2_mib[] = {
+       { "TxOctets",           0x000, 8        },
+       { "TxDropPkts",         0x020           },
+       { "TxQPKTQ0",           0x030           },
+       { "TxBroadcastPkts",    0x040           },
+       { "TxMulticastPkts",    0x050           },
+       { "TxUnicastPKts",      0x060           },
+       { "TxCollisions",       0x070           },
+       { "TxSingleCollision",  0x080           },
+       { "TxMultipleCollision", 0x090          },
+       { "TxDeferredCollision", 0x0a0          },
+       { "TxLateCollision",    0x0b0           },
+       { "TxExcessiveCollision", 0x0c0         },
+       { "TxFrameInDisc",      0x0d0           },
+       { "TxPausePkts",        0x0e0           },
+       { "TxQPKTQ1",           0x0f0           },
+       { "TxQPKTQ2",           0x100           },
+       { "TxQPKTQ3",           0x110           },
+       { "TxQPKTQ4",           0x120           },
+       { "TxQPKTQ5",           0x130           },
+       { "RxOctets",           0x140, 8        },
+       { "RxUndersizePkts",    0x160           },
+       { "RxPausePkts",        0x170           },
+       { "RxPkts64Octets",     0x180           },
+       { "RxPkts65to127Octets", 0x190          },
+       { "RxPkts128to255Octets", 0x1a0         },
+       { "RxPkts256to511Octets", 0x1b0         },
+       { "RxPkts512to1023Octets", 0x1c0        },
+       { "RxPkts1024toMaxPktsOctets", 0x1d0    },
+       { "RxOversizePkts",     0x1e0           },
+       { "RxJabbers",          0x1f0           },
+       { "RxAlignmentErrors",  0x200           },
+       { "RxFCSErrors",        0x210           },
+       { "RxGoodOctets",       0x220, 8        },
+       { "RxDropPkts",         0x240           },
+       { "RxUnicastPkts",      0x250           },
+       { "RxMulticastPkts",    0x260           },
+       { "RxBroadcastPkts",    0x270           },
+       { "RxSAChanges",        0x280           },
+       { "RxFragments",        0x290           },
+       { "RxJumboPkt",         0x2a0           },
+       { "RxSymblErr",         0x2b0           },
+       { "InRangeErrCount",    0x2c0           },
+       { "OutRangeErrCount",   0x2d0           },
+       { "EEELpiEvent",        0x2e0           },
+       { "EEELpiDuration",     0x2f0           },
+       { "RxDiscard",          0x300, 8        },
+       { "TxQPKTQ6",           0x320           },
+       { "TxQPKTQ7",           0x330           },
+       { "TxPkts64Octets",     0x340           },
+       { "TxPkts65to127Octets", 0x350          },
+       { "TxPkts128to255Octets", 0x360         },
+       { "TxPkts256to511Ocets", 0x370          },
+       { "TxPkts512to1023Ocets", 0x380         },
+       { "TxPkts1024toMaxPktOcets", 0x390      },
+};
+
+#define BCM_SF2_STATS_SIZE     ARRAY_SIZE(bcm_sf2_mib)
+
+static void bcm_sf2_sw_get_strings(struct dsa_switch *ds,
+                                  int port, uint8_t *data)
+{
+       unsigned int i;
+
+       for (i = 0; i < BCM_SF2_STATS_SIZE; i++)
+               memcpy(data + i * ETH_GSTRING_LEN,
+                      bcm_sf2_mib[i].string, ETH_GSTRING_LEN);
+}
+
+static void bcm_sf2_sw_get_ethtool_stats(struct dsa_switch *ds,
+                                        int port, uint64_t *data)
+{
+       struct bcm_sf2_priv *priv = ds_to_priv(ds);
+       const struct bcm_sf2_hw_stats *s;
+       unsigned int i;
+       u64 val = 0;
+       u32 offset;
+
+       mutex_lock(&priv->stats_mutex);
+
+       /* Now fetch the per-port counters */
+       for (i = 0; i < BCM_SF2_STATS_SIZE; i++) {
+               s = &bcm_sf2_mib[i];
+
+               /* Do a latched 64-bit read if needed */
+               offset = s->reg + CORE_P_MIB_OFFSET(port);
+               if (s->sizeof_stat == 8)
+                       val = core_readq(priv, offset);
+               else
+                       val = core_readl(priv, offset);
+
+               data[i] = (u64)val;
+       }
+
+       mutex_unlock(&priv->stats_mutex);
+}
+
+static int bcm_sf2_sw_get_sset_count(struct dsa_switch *ds)
+{
+       return BCM_SF2_STATS_SIZE;
+}
+
+static char *bcm_sf2_sw_probe(struct mii_bus *bus, int sw_addr)
+{
+       return "Broadcom Starfighter 2";
+}
+
+static void bcm_sf2_imp_setup(struct dsa_switch *ds, int port)
+{
+       struct bcm_sf2_priv *priv = ds_to_priv(ds);
+       unsigned int i;
+       u32 reg, val;
+
+       /* Enable the port memories */
+       reg = core_readl(priv, CORE_MEM_PSM_VDD_CTRL);
+       reg &= ~P_TXQ_PSM_VDD(port);
+       core_writel(priv, reg, CORE_MEM_PSM_VDD_CTRL);
+
+       /* Enable Broadcast, Multicast, Unicast forwarding to IMP port */
+       reg = core_readl(priv, CORE_IMP_CTL);
+       reg |= (RX_BCST_EN | RX_MCST_EN | RX_UCST_EN);
+       reg &= ~(RX_DIS | TX_DIS);
+       core_writel(priv, reg, CORE_IMP_CTL);
+
+       /* Enable forwarding */
+       core_writel(priv, SW_FWDG_EN, CORE_SWMODE);
+
+       /* Enable IMP port in dumb mode */
+       reg = core_readl(priv, CORE_SWITCH_CTRL);
+       reg |= MII_DUMB_FWDG_EN;
+       core_writel(priv, reg, CORE_SWITCH_CTRL);
+
+       /* Resolve which bit controls the Broadcom tag */
+       switch (port) {
+       case 8:
+               val = BRCM_HDR_EN_P8;
+               break;
+       case 7:
+               val = BRCM_HDR_EN_P7;
+               break;
+       case 5:
+               val = BRCM_HDR_EN_P5;
+               break;
+       default:
+               val = 0;
+               break;
+       }
+
+       /* Enable Broadcom tags for IMP port */
+       reg = core_readl(priv, CORE_BRCM_HDR_CTRL);
+       reg |= val;
+       core_writel(priv, reg, CORE_BRCM_HDR_CTRL);
+
+       /* Enable reception Broadcom tag for CPU TX (switch RX) to
+        * allow us to tag outgoing frames
+        */
+       reg = core_readl(priv, CORE_BRCM_HDR_RX_DIS);
+       reg &= ~(1 << port);
+       core_writel(priv, reg, CORE_BRCM_HDR_RX_DIS);
+
+       /* Enable transmission of Broadcom tags from the switch (CPU RX) to
+        * allow delivering frames to the per-port net_devices
+        */
+       reg = core_readl(priv, CORE_BRCM_HDR_TX_DIS);
+       reg &= ~(1 << port);
+       core_writel(priv, reg, CORE_BRCM_HDR_TX_DIS);
+
+       /* Force link status for IMP port */
+       reg = core_readl(priv, CORE_STS_OVERRIDE_IMP);
+       reg |= (MII_SW_OR | LINK_STS);
+       core_writel(priv, reg, CORE_STS_OVERRIDE_IMP);
+
+       /* Enable the IMP Port to be in the same VLAN as the other ports
+        * on a per-port basis such that we only have Port i and IMP in
+        * the same VLAN.
+        */
+       for (i = 0; i < priv->hw_params.num_ports; i++) {
+               if (!((1 << i) & ds->phys_port_mask))
+                       continue;
+
+               reg = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(i));
+               reg |= (1 << port);
+               core_writel(priv, reg, CORE_PORT_VLAN_CTL_PORT(i));
+       }
+}
+
+static void bcm_sf2_port_setup(struct dsa_switch *ds, int port)
+{
+       struct bcm_sf2_priv *priv = ds_to_priv(ds);
+       u32 reg;
+
+       /* Clear the memory power down */
+       reg = core_readl(priv, CORE_MEM_PSM_VDD_CTRL);
+       reg &= ~P_TXQ_PSM_VDD(port);
+       core_writel(priv, reg, CORE_MEM_PSM_VDD_CTRL);
+
+       /* Clear the Rx and Tx disable bits and set to no spanning tree */
+       core_writel(priv, 0, CORE_G_PCTL_PORT(port));
+
+       /* Enable port 7 interrupts to get notified */
+       if (port == 7)
+               intrl2_1_mask_clear(priv, P_IRQ_MASK(P7_IRQ_OFF));
+
+       /* Set this port, and only this one to be in the default VLAN */
+       reg = core_readl(priv, CORE_PORT_VLAN_CTL_PORT(port));
+       reg &= ~PORT_VLAN_CTRL_MASK;
+       reg |= (1 << port);
+       core_writel(priv, reg, CORE_PORT_VLAN_CTL_PORT(port));
+}
+
+static void bcm_sf2_port_disable(struct dsa_switch *ds, int port)
+{
+       struct bcm_sf2_priv *priv = ds_to_priv(ds);
+       u32 off, reg;
+
+       if (dsa_is_cpu_port(ds, port))
+               off = CORE_IMP_CTL;
+       else
+               off = CORE_G_PCTL_PORT(port);
+
+       reg = core_readl(priv, off);
+       reg |= RX_DIS | TX_DIS;
+       core_writel(priv, reg, off);
+
+       /* Power down the port memory */
+       reg = core_readl(priv, CORE_MEM_PSM_VDD_CTRL);
+       reg |= P_TXQ_PSM_VDD(port);
+       core_writel(priv, reg, CORE_MEM_PSM_VDD_CTRL);
+}
+
+static irqreturn_t bcm_sf2_switch_0_isr(int irq, void *dev_id)
+{
+       struct bcm_sf2_priv *priv = dev_id;
+
+       priv->irq0_stat = intrl2_0_readl(priv, INTRL2_CPU_STATUS) &
+                               ~priv->irq0_mask;
+       intrl2_0_writel(priv, priv->irq0_stat, INTRL2_CPU_CLEAR);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t bcm_sf2_switch_1_isr(int irq, void *dev_id)
+{
+       struct bcm_sf2_priv *priv = dev_id;
+
+       priv->irq1_stat = intrl2_1_readl(priv, INTRL2_CPU_STATUS) &
+                               ~priv->irq1_mask;
+       intrl2_1_writel(priv, priv->irq1_stat, INTRL2_CPU_CLEAR);
+
+       if (priv->irq1_stat & P_LINK_UP_IRQ(P7_IRQ_OFF))
+               priv->port_sts[7].link = 1;
+       if (priv->irq1_stat & P_LINK_DOWN_IRQ(P7_IRQ_OFF))
+               priv->port_sts[7].link = 0;
+
+       return IRQ_HANDLED;
+}
+
+static int bcm_sf2_sw_setup(struct dsa_switch *ds)
+{
+       const char *reg_names[BCM_SF2_REGS_NUM] = BCM_SF2_REGS_NAME;
+       struct bcm_sf2_priv *priv = ds_to_priv(ds);
+       struct device_node *dn;
+       void __iomem **base;
+       unsigned int port;
+       unsigned int i;
+       u32 reg, rev;
+       int ret;
+
+       spin_lock_init(&priv->indir_lock);
+       mutex_init(&priv->stats_mutex);
+
+       /* All the interesting properties are at the parent device_node
+        * level
+        */
+       dn = ds->pd->of_node->parent;
+
+       priv->irq0 = irq_of_parse_and_map(dn, 0);
+       priv->irq1 = irq_of_parse_and_map(dn, 1);
+
+       base = &priv->core;
+       for (i = 0; i < BCM_SF2_REGS_NUM; i++) {
+               *base = of_iomap(dn, i);
+               if (*base == NULL) {
+                       pr_err("unable to find register: %s\n", reg_names[i]);
+                       return -ENODEV;
+               }
+               base++;
+       }
+
+       /* Disable all interrupts and request them */
+       intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET);
+       intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);
+       intrl2_0_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
+       intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET);
+       intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);
+       intrl2_1_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
+
+       ret = request_irq(priv->irq0, bcm_sf2_switch_0_isr, 0,
+                         "switch_0", priv);
+       if (ret < 0) {
+               pr_err("failed to request switch_0 IRQ\n");
+               goto out_unmap;
+       }
+
+       ret = request_irq(priv->irq1, bcm_sf2_switch_1_isr, 0,
+                         "switch_1", priv);
+       if (ret < 0) {
+               pr_err("failed to request switch_1 IRQ\n");
+               goto out_free_irq0;
+       }
+
+       /* Reset the MIB counters */
+       reg = core_readl(priv, CORE_GMNCFGCFG);
+       reg |= RST_MIB_CNT;
+       core_writel(priv, reg, CORE_GMNCFGCFG);
+       reg &= ~RST_MIB_CNT;
+       core_writel(priv, reg, CORE_GMNCFGCFG);
+
+       /* Get the maximum number of ports for this switch */
+       priv->hw_params.num_ports = core_readl(priv, CORE_IMP0_PRT_ID) + 1;
+       if (priv->hw_params.num_ports > DSA_MAX_PORTS)
+               priv->hw_params.num_ports = DSA_MAX_PORTS;
+
+       /* Assume a single GPHY setup if we can't read that property */
+       if (of_property_read_u32(dn, "brcm,num-gphy",
+                                &priv->hw_params.num_gphy))
+               priv->hw_params.num_gphy = 1;
+
+       /* Enable all valid ports and disable those unused */
+       for (port = 0; port < priv->hw_params.num_ports; port++) {
+               /* IMP port receives special treatment */
+               if ((1 << port) & ds->phys_port_mask)
+                       bcm_sf2_port_setup(ds, port);
+               else if (dsa_is_cpu_port(ds, port))
+                       bcm_sf2_imp_setup(ds, port);
+               else
+                       bcm_sf2_port_disable(ds, port);
+       }
+
+       /* Include the pseudo-PHY address and the broadcast PHY address to
+        * divert reads towards our workaround
+        */
+       ds->phys_mii_mask |= ((1 << 30) | (1 << 0));
+
+       rev = reg_readl(priv, REG_SWITCH_REVISION);
+       priv->hw_params.top_rev = (rev >> SWITCH_TOP_REV_SHIFT) &
+                                       SWITCH_TOP_REV_MASK;
+       priv->hw_params.core_rev = (rev & SF2_REV_MASK);
+
+       pr_info("Starfighter 2 top: %x.%02x, core: %x.%02x base: 0x%p, IRQs: %d, %d\n",
+               priv->hw_params.top_rev >> 8, priv->hw_params.top_rev & 0xff,
+               priv->hw_params.core_rev >> 8, priv->hw_params.core_rev & 0xff,
+               priv->core, priv->irq0, priv->irq1);
+
+       return 0;
+
+out_free_irq0:
+       free_irq(priv->irq0, priv);
+out_unmap:
+       base = &priv->core;
+       for (i = 0; i < BCM_SF2_REGS_NUM; i++) {
+               iounmap(*base);
+               base++;
+       }
+       return ret;
+}
+
+static int bcm_sf2_sw_set_addr(struct dsa_switch *ds, u8 *addr)
+{
+       return 0;
+}
+
+static int bcm_sf2_sw_indir_rw(struct dsa_switch *ds, int op, int addr,
+                              int regnum, u16 val)
+{
+       struct bcm_sf2_priv *priv = ds_to_priv(ds);
+       int ret = 0;
+       u32 reg;
+
+       reg = reg_readl(priv, REG_SWITCH_CNTRL);
+       reg |= MDIO_MASTER_SEL;
+       reg_writel(priv, reg, REG_SWITCH_CNTRL);
+
+       /* Page << 8 | offset */
+       reg = 0x70;
+       reg <<= 2;
+       core_writel(priv, addr, reg);
+
+       /* Page << 8 | offset */
+       reg = 0x80 << 8 | regnum << 1;
+       reg <<= 2;
+
+       if (op)
+               ret = core_readl(priv, reg);
+       else
+               core_writel(priv, val, reg);
+
+       reg = reg_readl(priv, REG_SWITCH_CNTRL);
+       reg &= ~MDIO_MASTER_SEL;
+       reg_writel(priv, reg, REG_SWITCH_CNTRL);
+
+       return ret & 0xffff;
+}
+
+static int bcm_sf2_sw_phy_read(struct dsa_switch *ds, int addr, int regnum)
+{
+       /* Intercept reads from the MDIO broadcast address or Broadcom
+        * pseudo-PHY address
+        */
+       switch (addr) {
+       case 0:
+       case 30:
+               return bcm_sf2_sw_indir_rw(ds, 1, addr, regnum, 0);
+       default:
+               return 0xffff;
+       }
+}
+
+static int bcm_sf2_sw_phy_write(struct dsa_switch *ds, int addr, int regnum,
+                               u16 val)
+{
+       /* Intercept writes to the MDIO broadcast address or Broadcom
+        * pseudo-PHY address
+        */
+       switch (addr) {
+       case 0:
+       case 30:
+               bcm_sf2_sw_indir_rw(ds, 0, addr, regnum, val);
+               break;
+       }
+
+       return 0;
+}
+
+static void bcm_sf2_sw_adjust_link(struct dsa_switch *ds, int port,
+                                  struct phy_device *phydev)
+{
+       struct bcm_sf2_priv *priv = ds_to_priv(ds);
+       u32 id_mode_dis = 0, port_mode;
+       const char *str = NULL;
+       u32 reg;
+
+       switch (phydev->interface) {
+       case PHY_INTERFACE_MODE_RGMII:
+               str = "RGMII (no delay)";
+               id_mode_dis = 1;
+       case PHY_INTERFACE_MODE_RGMII_TXID:
+               if (!str)
+                       str = "RGMII (TX delay)";
+               port_mode = EXT_GPHY;
+               break;
+       case PHY_INTERFACE_MODE_MII:
+               str = "MII";
+               port_mode = EXT_EPHY;
+               break;
+       case PHY_INTERFACE_MODE_REVMII:
+               str = "Reverse MII";
+               port_mode = EXT_REVMII;
+               break;
+       default:
+               goto force_link;
+       }
+
+       /* Clear id_mode_dis bit, and the existing port mode, but
+        * make sure we enable the RGMII block for data to pass
+        */
+       reg = reg_readl(priv, REG_RGMII_CNTRL_P(port));
+       reg &= ~ID_MODE_DIS;
+       reg &= ~(PORT_MODE_MASK << PORT_MODE_SHIFT);
+       reg &= ~(RX_PAUSE_EN | TX_PAUSE_EN);
+
+       reg |= port_mode | RGMII_MODE_EN;
+       if (id_mode_dis)
+               reg |= ID_MODE_DIS;
+
+       if (phydev->pause) {
+               if (phydev->asym_pause)
+                       reg |= TX_PAUSE_EN;
+               reg |= RX_PAUSE_EN;
+       }
+
+       reg_writel(priv, reg, REG_RGMII_CNTRL_P(port));
+
+       pr_info("Port %d configured for %s\n", port, str);
+
+force_link:
+       /* Force link settings detected from the PHY */
+       reg = SW_OVERRIDE;
+       switch (phydev->speed) {
+       case SPEED_1000:
+               reg |= SPDSTS_1000 << SPEED_SHIFT;
+               break;
+       case SPEED_100:
+               reg |= SPDSTS_100 << SPEED_SHIFT;
+               break;
+       }
+
+       if (phydev->link)
+               reg |= LINK_STS;
+       if (phydev->duplex == DUPLEX_FULL)
+               reg |= DUPLX_MODE;
+
+       core_writel(priv, reg, CORE_STS_OVERRIDE_GMIIP_PORT(port));
+}
+
+static void bcm_sf2_sw_fixed_link_update(struct dsa_switch *ds, int port,
+                                        struct fixed_phy_status *status)
+{
+       struct bcm_sf2_priv *priv = ds_to_priv(ds);
+       u32 link, duplex, pause, speed;
+       u32 reg;
+
+       link = core_readl(priv, CORE_LNKSTS);
+       duplex = core_readl(priv, CORE_DUPSTS);
+       pause = core_readl(priv, CORE_PAUSESTS);
+       speed = core_readl(priv, CORE_SPDSTS);
+
+       speed >>= (port * SPDSTS_SHIFT);
+       speed &= SPDSTS_MASK;
+
+       status->link = 0;
+
+       /* Port 7 is special as we do not get link status from CORE_LNKSTS,
+        * which means that we need to force the link at the port override
+        * level to get the data to flow. We do use what the interrupt handler
+        * did determine before.
+        */
+       if (port == 7) {
+               status->link = priv->port_sts[port].link;
+               reg = core_readl(priv, CORE_STS_OVERRIDE_GMIIP_PORT(7));
+               reg |= SW_OVERRIDE;
+               if (status->link)
+                       reg |= LINK_STS;
+               else
+                       reg &= ~LINK_STS;
+               core_writel(priv, reg, CORE_STS_OVERRIDE_GMIIP_PORT(7));
+               status->duplex = 1;
+       } else {
+               status->link = !!(link & (1 << port));
+               status->duplex = !!(duplex & (1 << port));
+       }
+
+       switch (speed) {
+       case SPDSTS_10:
+               status->speed = SPEED_10;
+               break;
+       case SPDSTS_100:
+               status->speed = SPEED_100;
+               break;
+       case SPDSTS_1000:
+               status->speed = SPEED_1000;
+               break;
+       }
+
+       if ((pause & (1 << port)) &&
+           (pause & (1 << (port + PAUSESTS_TX_PAUSE_SHIFT)))) {
+               status->asym_pause = 1;
+               status->pause = 1;
+       }
+
+       if (pause & (1 << port))
+               status->pause = 1;
+}
+
+static struct dsa_switch_driver bcm_sf2_switch_driver = {
+       .tag_protocol           = htons(ETH_P_BRCMTAG),
+       .priv_size              = sizeof(struct bcm_sf2_priv),
+       .probe                  = bcm_sf2_sw_probe,
+       .setup                  = bcm_sf2_sw_setup,
+       .set_addr               = bcm_sf2_sw_set_addr,
+       .phy_read               = bcm_sf2_sw_phy_read,
+       .phy_write              = bcm_sf2_sw_phy_write,
+       .get_strings            = bcm_sf2_sw_get_strings,
+       .get_ethtool_stats      = bcm_sf2_sw_get_ethtool_stats,
+       .get_sset_count         = bcm_sf2_sw_get_sset_count,
+       .adjust_link            = bcm_sf2_sw_adjust_link,
+       .fixed_link_update      = bcm_sf2_sw_fixed_link_update,
+};
+
+static int __init bcm_sf2_init(void)
+{
+       register_switch_driver(&bcm_sf2_switch_driver);
+
+       return 0;
+}
+module_init(bcm_sf2_init);
+
+static void __exit bcm_sf2_exit(void)
+{
+       unregister_switch_driver(&bcm_sf2_switch_driver);
+}
+module_exit(bcm_sf2_exit);
+
+MODULE_AUTHOR("Broadcom Corporation");
+MODULE_DESCRIPTION("Driver for Broadcom Starfighter 2 ethernet switch chip");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:brcm-sf2");
diff --git a/drivers/net/dsa/bcm_sf2.h b/drivers/net/dsa/bcm_sf2.h
new file mode 100644 (file)
index 0000000..260bab3
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Broadcom Starfighter2 private context
+ *
+ * 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.
+ */
+
+#ifndef __BCM_SF2_H
+#define __BCM_SF2_H
+
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/mii.h>
+
+#include <net/dsa.h>
+
+#include "bcm_sf2_regs.h"
+
+struct bcm_sf2_hw_params {
+       u16     top_rev;
+       u16     core_rev;
+       u32     num_gphy;
+       u8      num_acb_queue;
+       u8      num_rgmii;
+       u8      num_ports;
+       u8      fcb_pause_override:1;
+       u8      acb_packets_inflight:1;
+};
+
+#define BCM_SF2_REGS_NAME {\
+       "core", "reg", "intrl2_0", "intrl2_1", "fcb", "acb" \
+}
+
+#define BCM_SF2_REGS_NUM       6
+
+struct bcm_sf2_port_status {
+       unsigned int link;
+};
+
+struct bcm_sf2_priv {
+       /* Base registers, keep those in order with BCM_SF2_REGS_NAME */
+       void __iomem                    *core;
+       void __iomem                    *reg;
+       void __iomem                    *intrl2_0;
+       void __iomem                    *intrl2_1;
+       void __iomem                    *fcb;
+       void __iomem                    *acb;
+
+       /* spinlock protecting access to the indirect registers */
+       spinlock_t                      indir_lock;
+
+       int                             irq0;
+       int                             irq1;
+       u32                             irq0_stat;
+       u32                             irq0_mask;
+       u32                             irq1_stat;
+       u32                             irq1_mask;
+
+       /* Mutex protecting access to the MIB counters */
+       struct mutex                    stats_mutex;
+
+       struct bcm_sf2_hw_params        hw_params;
+
+       struct bcm_sf2_port_status      port_sts[DSA_MAX_PORTS];
+};
+
+struct bcm_sf2_hw_stats {
+       const char      *string;
+       u16             reg;
+       u8              sizeof_stat;
+};
+
+#define SF2_IO_MACRO(name) \
+static inline u32 name##_readl(struct bcm_sf2_priv *priv, u32 off)     \
+{                                                                      \
+       return __raw_readl(priv->name + off);                           \
+}                                                                      \
+static inline void name##_writel(struct bcm_sf2_priv *priv,            \
+                                 u32 val, u32 off)                     \
+{                                                                      \
+       __raw_writel(val, priv->name + off);                            \
+}                                                                      \
+
+/* Accesses to 64-bits register requires us to latch the hi/lo pairs
+ * using the REG_DIR_DATA_{READ,WRITE} ancillary registers. The 'indir_lock'
+ * spinlock is automatically grabbed and released to provide relative
+ * atomiticy with latched reads/writes.
+ */
+#define SF2_IO64_MACRO(name) \
+static inline u64 name##_readq(struct bcm_sf2_priv *priv, u32 off)     \
+{                                                                      \
+       u32 indir, dir;                                                 \
+       spin_lock(&priv->indir_lock);                                   \
+       indir = reg_readl(priv, REG_DIR_DATA_READ);                     \
+       dir = __raw_readl(priv->name + off);                            \
+       spin_unlock(&priv->indir_lock);                                 \
+       return (u64)indir << 32 | dir;                                  \
+}                                                                      \
+static inline void name##_writeq(struct bcm_sf2_priv *priv, u32 off,   \
+                                                       u64 val)        \
+{                                                                      \
+       spin_lock(&priv->indir_lock);                                   \
+       reg_writel(priv, upper_32_bits(val), REG_DIR_DATA_WRITE);       \
+       __raw_writel(lower_32_bits(val), priv->name + off);             \
+       spin_unlock(&priv->indir_lock);                                 \
+}
+
+#define SWITCH_INTR_L2(which)                                          \
+static inline void intrl2_##which##_mask_clear(struct bcm_sf2_priv *priv, \
+                                               u32 mask)               \
+{                                                                      \
+       intrl2_##which##_writel(priv, mask, INTRL2_CPU_MASK_CLEAR);     \
+       priv->irq##which##_mask &= ~(mask);                             \
+}                                                                      \
+static inline void intrl2_##which##_mask_set(struct bcm_sf2_priv *priv, \
+                                               u32 mask)               \
+{                                                                      \
+       intrl2_## which##_writel(priv, mask, INTRL2_CPU_MASK_SET);      \
+       priv->irq##which##_mask |= (mask);                              \
+}                                                                      \
+
+SF2_IO_MACRO(core);
+SF2_IO_MACRO(reg);
+SF2_IO64_MACRO(core);
+SF2_IO_MACRO(intrl2_0);
+SF2_IO_MACRO(intrl2_1);
+SF2_IO_MACRO(fcb);
+SF2_IO_MACRO(acb);
+
+SWITCH_INTR_L2(0);
+SWITCH_INTR_L2(1);
+
+#endif /* __BCM_SF2_H */
diff --git a/drivers/net/dsa/bcm_sf2_regs.h b/drivers/net/dsa/bcm_sf2_regs.h
new file mode 100644 (file)
index 0000000..885c231
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * Broadcom Starfighter 2 switch register defines
+ *
+ * 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.
+ */
+#ifndef __BCM_SF2_REGS_H
+#define __BCM_SF2_REGS_H
+
+/* Register set relative to 'REG' */
+#define REG_SWITCH_CNTRL               0x00
+#define  MDIO_MASTER_SEL               (1 << 0)
+
+#define REG_SWITCH_STATUS              0x04
+#define REG_DIR_DATA_WRITE             0x08
+#define REG_DIR_DATA_READ              0x0C
+
+#define REG_SWITCH_REVISION            0x18
+#define  SF2_REV_MASK                  0xffff
+#define  SWITCH_TOP_REV_SHIFT          16
+#define  SWITCH_TOP_REV_MASK           0xffff
+
+#define REG_PHY_REVISION               0x1C
+
+#define REG_SPHY_CNTRL                 0x2C
+#define  IDDQ_BIAS                     (1 << 0)
+#define  EXT_PWR_DOWN                  (1 << 1)
+#define  FORCE_DLL_EN                  (1 << 2)
+#define  IDDQ_GLOBAL_PWR               (1 << 3)
+#define  CK25_DIS                      (1 << 4)
+#define  PHY_RESET                     (1 << 5)
+#define  PHY_PHYAD_SHIFT               8
+#define  PHY_PHYAD_MASK                        0x1F
+
+#define REG_RGMII_0_BASE               0x34
+#define REG_RGMII_CNTRL                        0x00
+#define REG_RGMII_IB_STATUS            0x04
+#define REG_RGMII_RX_CLOCK_DELAY_CNTRL 0x08
+#define REG_RGMII_CNTRL_SIZE           0x0C
+#define REG_RGMII_CNTRL_P(x)           (REG_RGMII_0_BASE + \
+                                       ((x) * REG_RGMII_CNTRL_SIZE))
+/* Relative to REG_RGMII_CNTRL */
+#define  RGMII_MODE_EN                 (1 << 0)
+#define  ID_MODE_DIS                   (1 << 1)
+#define  PORT_MODE_SHIFT               2
+#define  INT_EPHY                      (0 << PORT_MODE_SHIFT)
+#define  INT_GPHY                      (1 << PORT_MODE_SHIFT)
+#define  EXT_EPHY                      (2 << PORT_MODE_SHIFT)
+#define  EXT_GPHY                      (3 << PORT_MODE_SHIFT)
+#define  EXT_REVMII                    (4 << PORT_MODE_SHIFT)
+#define  PORT_MODE_MASK                        0x7
+#define  RVMII_REF_SEL                 (1 << 5)
+#define  RX_PAUSE_EN                   (1 << 6)
+#define  TX_PAUSE_EN                   (1 << 7)
+#define  TX_CLK_STOP_EN                        (1 << 8)
+#define  LPI_COUNT_SHIFT               9
+#define  LPI_COUNT_MASK                        0x3F
+
+/* Register set relative to 'INTRL2_0' and 'INTRL2_1' */
+#define INTRL2_CPU_STATUS              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
+
+/* Shared INTRL2_0 and INTRL2_ interrupt sources macros */
+#define P_LINK_UP_IRQ(x)               (1 << (0 + (x)))
+#define P_LINK_DOWN_IRQ(x)             (1 << (1 + (x)))
+#define P_ENERGY_ON_IRQ(x)             (1 << (2 + (x)))
+#define P_ENERGY_OFF_IRQ(x)            (1 << (3 + (x)))
+#define P_GPHY_IRQ(x)                  (1 << (4 + (x)))
+#define P_NUM_IRQ                      5
+#define P_IRQ_MASK(x)                  (P_LINK_UP_IRQ((x)) | \
+                                        P_LINK_DOWN_IRQ((x)) | \
+                                        P_ENERGY_ON_IRQ((x)) | \
+                                        P_ENERGY_OFF_IRQ((x)) | \
+                                        P_GPHY_IRQ((x)))
+
+/* INTRL2_0 interrupt sources */
+#define P0_IRQ_OFF                     0
+#define MEM_DOUBLE_IRQ                 (1 << 5)
+#define EEE_LPI_IRQ                    (1 << 6)
+#define P5_CPU_WAKE_IRQ                        (1 << 7)
+#define P8_CPU_WAKE_IRQ                        (1 << 8)
+#define P7_CPU_WAKE_IRQ                        (1 << 9)
+#define IEEE1588_IRQ                   (1 << 10)
+#define MDIO_ERR_IRQ                   (1 << 11)
+#define MDIO_DONE_IRQ                  (1 << 12)
+#define GISB_ERR_IRQ                   (1 << 13)
+#define UBUS_ERR_IRQ                   (1 << 14)
+#define FAILOVER_ON_IRQ                        (1 << 15)
+#define FAILOVER_OFF_IRQ               (1 << 16)
+#define TCAM_SOFT_ERR_IRQ              (1 << 17)
+
+/* INTRL2_1 interrupt sources */
+#define P7_IRQ_OFF                     0
+#define P_IRQ_OFF(x)                   ((6 - (x)) * P_NUM_IRQ)
+
+/* Register set relative to 'CORE' */
+#define CORE_G_PCTL_PORT0              0x00000
+#define CORE_G_PCTL_PORT(x)            (CORE_G_PCTL_PORT0 + (x * 0x4))
+#define CORE_IMP_CTL                   0x00020
+#define  RX_DIS                                (1 << 0)
+#define  TX_DIS                                (1 << 1)
+#define  RX_BCST_EN                    (1 << 2)
+#define  RX_MCST_EN                    (1 << 3)
+#define  RX_UCST_EN                    (1 << 4)
+#define  G_MISTP_STATE_SHIFT           5
+#define  G_MISTP_NO_STP                        (0 << G_MISTP_STATE_SHIFT)
+#define  G_MISTP_DIS_STATE             (1 << G_MISTP_STATE_SHIFT)
+#define  G_MISTP_BLOCK_STATE           (2 << G_MISTP_STATE_SHIFT)
+#define  G_MISTP_LISTEN_STATE          (3 << G_MISTP_STATE_SHIFT)
+#define  G_MISTP_LEARN_STATE           (4 << G_MISTP_STATE_SHIFT)
+#define  G_MISTP_FWD_STATE             (5 << G_MISTP_STATE_SHIFT)
+#define  G_MISTP_STATE_MASK            0x7
+
+#define CORE_SWMODE                    0x0002c
+#define  SW_FWDG_MODE                  (1 << 0)
+#define  SW_FWDG_EN                    (1 << 1)
+#define  RTRY_LMT_DIS                  (1 << 2)
+
+#define CORE_STS_OVERRIDE_IMP          0x00038
+#define  GMII_SPEED_UP_2G              (1 << 6)
+#define  MII_SW_OR                     (1 << 7)
+
+#define CORE_NEW_CTRL                  0x00084
+#define  IP_MC                         (1 << 0)
+#define  OUTRANGEERR_DISCARD           (1 << 1)
+#define  INRANGEERR_DISCARD            (1 << 2)
+#define  CABLE_DIAG_LEN                        (1 << 3)
+#define  OVERRIDE_AUTO_PD_WAR          (1 << 4)
+#define  EN_AUTO_PD_WAR                        (1 << 5)
+#define  UC_FWD_EN                     (1 << 6)
+#define  MC_FWD_EN                     (1 << 7)
+
+#define CORE_SWITCH_CTRL               0x00088
+#define  MII_DUMB_FWDG_EN              (1 << 6)
+
+#define CORE_SFT_LRN_CTRL              0x000f8
+#define  SW_LEARN_CNTL(x)              (1 << (x))
+
+#define CORE_STS_OVERRIDE_GMIIP_PORT(x)        (0x160 + (x) * 4)
+#define  LINK_STS                      (1 << 0)
+#define  DUPLX_MODE                    (1 << 1)
+#define  SPEED_SHIFT                   2
+#define  SPEED_MASK                    0x3
+#define  RXFLOW_CNTL                   (1 << 4)
+#define  TXFLOW_CNTL                   (1 << 5)
+#define  SW_OVERRIDE                   (1 << 6)
+
+#define CORE_WATCHDOG_CTRL             0x001e4
+#define  SOFTWARE_RESET                        (1 << 7)
+#define  EN_CHIP_RST                   (1 << 6)
+#define  EN_SW_RESET                   (1 << 4)
+
+#define CORE_LNKSTS                    0x00400
+#define  LNK_STS_MASK                  0x1ff
+
+#define CORE_SPDSTS                    0x00410
+#define  SPDSTS_10                     0
+#define  SPDSTS_100                    1
+#define  SPDSTS_1000                   2
+#define  SPDSTS_SHIFT                  2
+#define  SPDSTS_MASK                   0x3
+
+#define CORE_DUPSTS                    0x00420
+#define  CORE_DUPSTS_MASK              0x1ff
+
+#define CORE_PAUSESTS                  0x00428
+#define  PAUSESTS_TX_PAUSE_SHIFT       9
+
+#define CORE_GMNCFGCFG                 0x0800
+#define  RST_MIB_CNT                   (1 << 0)
+#define  RXBPDU_EN                     (1 << 1)
+
+#define CORE_IMP0_PRT_ID               0x0804
+
+#define CORE_BRCM_HDR_CTRL             0x0080c
+#define  BRCM_HDR_EN_P8                        (1 << 0)
+#define  BRCM_HDR_EN_P5                        (1 << 1)
+#define  BRCM_HDR_EN_P7                        (1 << 2)
+
+#define CORE_BRCM_HDR_CTRL2            0x0828
+
+#define CORE_HL_PRTC_CTRL              0x0940
+#define  ARP_EN                                (1 << 0)
+#define  RARP_EN                       (1 << 1)
+#define  DHCP_EN                       (1 << 2)
+#define  ICMPV4_EN                     (1 << 3)
+#define  ICMPV6_EN                     (1 << 4)
+#define  ICMPV6_FWD_MODE               (1 << 5)
+#define  IGMP_DIP_EN                   (1 << 8)
+#define  IGMP_RPTLVE_EN                        (1 << 9)
+#define  IGMP_RTPLVE_FWD_MODE          (1 << 10)
+#define  IGMP_QRY_EN                   (1 << 11)
+#define  IGMP_QRY_FWD_MODE             (1 << 12)
+#define  IGMP_UKN_EN                   (1 << 13)
+#define  IGMP_UKN_FWD_MODE             (1 << 14)
+#define  MLD_RPTDONE_EN                        (1 << 15)
+#define  MLD_RPTDONE_FWD_MODE          (1 << 16)
+#define  MLD_QRY_EN                    (1 << 17)
+#define  MLD_QRY_FWD_MODE              (1 << 18)
+
+#define CORE_RST_MIB_CNT_EN            0x0950
+
+#define CORE_BRCM_HDR_RX_DIS           0x0980
+#define CORE_BRCM_HDR_TX_DIS           0x0988
+
+#define CORE_MEM_PSM_VDD_CTRL          0x2380
+#define  P_TXQ_PSM_VDD_SHIFT           2
+#define  P_TXQ_PSM_VDD_MASK            0x3
+#define  P_TXQ_PSM_VDD(x)              (P_TXQ_PSM_VDD_MASK << \
+                                       ((x) * P_TXQ_PSM_VDD_SHIFT))
+
+#define        CORE_P0_MIB_OFFSET              0x8000
+#define P_MIB_SIZE                     0x400
+#define CORE_P_MIB_OFFSET(x)           (CORE_P0_MIB_OFFSET + (x) * P_MIB_SIZE)
+
+#define CORE_PORT_VLAN_CTL_PORT(x)     (0xc400 + ((x) * 0x8))
+#define  PORT_VLAN_CTRL_MASK           0x1ff
+
+#endif /* __BCM_SF2_REGS_H */
index a968654b631d28a860dcd83b8c9b728189c196b2..4547a1b8b958bab25ed6cd73ccd3d0b62112dfaa 100644 (file)
@@ -695,9 +695,9 @@ el3_tx_timeout (struct net_device *dev)
        int ioaddr = dev->base_addr;
 
        /* Transmitter timeout, serious problems. */
-       pr_warning("%s: transmit timed out, Tx_status %2.2x status %4.4x Tx FIFO room %d.\n",
-                  dev->name, inb(ioaddr + TX_STATUS), inw(ioaddr + EL3_STATUS),
-                  inw(ioaddr + TX_FREE));
+       pr_warn("%s: transmit timed out, Tx_status %2.2x status %4.4x Tx FIFO room %d\n",
+               dev->name, inb(ioaddr + TX_STATUS), inw(ioaddr + EL3_STATUS),
+               inw(ioaddr + TX_FREE));
        dev->stats.tx_errors++;
        dev->trans_start = jiffies; /* prevent tx timeout */
        /* Issue TX_RESET and TX_START commands. */
index 94c656f5a05ddbe9a09e505009466961a8e119a2..942fb0d5aacebf0b7f565836979b7d61ab3b9cfb 100644 (file)
@@ -515,7 +515,7 @@ static struct net_device *corkscrew_scan(int unit)
                        if (pnp_device_attach(idev) < 0)
                                continue;
                        if (pnp_activate_dev(idev) < 0) {
-                               pr_warning("pnp activate failed (out of resources?)\n");
+                               pr_warn("pnp activate failed (out of resources?)\n");
                                pnp_device_detach(idev);
                                continue;
                        }
@@ -659,7 +659,7 @@ static int corkscrew_setup(struct net_device *dev, int ioaddr,
        pr_cont(", IRQ %d\n", dev->irq);
        /* Tell them about an invalid IRQ. */
        if (corkscrew_debug && (dev->irq <= 0 || dev->irq > 15))
-               pr_warning(" *** Warning: this IRQ is unlikely to work! ***\n");
+               pr_warn(" *** Warning: this IRQ is unlikely to work! ***\n");
 
        {
                static const char * const ram_split[] = {
@@ -967,13 +967,13 @@ static void corkscrew_timeout(struct net_device *dev)
        struct corkscrew_private *vp = netdev_priv(dev);
        int ioaddr = dev->base_addr;
 
-       pr_warning("%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
-              dev->name, inb(ioaddr + TxStatus),
-              inw(ioaddr + EL3_STATUS));
+       pr_warn("%s: transmit timed out, tx_status %2.2x status %4.4x\n",
+               dev->name, inb(ioaddr + TxStatus),
+               inw(ioaddr + EL3_STATUS));
        /* Slight code bloat to be user friendly. */
        if ((inb(ioaddr + TxStatus) & 0x88) == 0x88)
-               pr_warning("%s: Transmitter encountered 16 collisions --"
-                      " network cable problem?\n", dev->name);
+               pr_warn("%s: Transmitter encountered 16 collisions -- network cable problem?\n",
+                       dev->name);
 #ifndef final_version
        pr_debug("  Flags; bus-master %d, full %d; dirty %d current %d.\n",
               vp->full_bus_master_tx, vp->tx_full, vp->dirty_tx,
@@ -1382,13 +1382,10 @@ static int boomerang_rx(struct net_device *dev)
                                temp = skb_put(skb, pkt_len);
                                /* Remove this checking code for final release. */
                                if (isa_bus_to_virt(vp->rx_ring[entry].addr) != temp)
-                                       pr_warning("%s: Warning -- the skbuff addresses do not match"
-                                            " in boomerang_rx: %p vs. %p / %p.\n",
-                                            dev->name,
-                                            isa_bus_to_virt(vp->
-                                                        rx_ring[entry].
-                                                        addr), skb->head,
-                                            temp);
+                                       pr_warn("%s: Warning -- the skbuff addresses do not match in boomerang_rx: %p vs. %p / %p\n",
+                                               dev->name,
+                                               isa_bus_to_virt(vp->rx_ring[entry].addr),
+                                               skb->head, temp);
                                rx_nocopy++;
                        }
                        skb->protocol = eth_type_trans(skb, dev);
index 059c7414e30318b3ccaab436a248d63319823369..2b92d712f212369aa61128a2b4a40595ce6079a4 100644 (file)
@@ -1310,8 +1310,8 @@ static int vortex_probe1(struct device *gendev, void __iomem *ioaddr, int irq,
                pr_cont(", IRQ %d\n", dev->irq);
        /* Tell them about an invalid IRQ. */
        if (dev->irq <= 0 || dev->irq >= nr_irqs)
-               pr_warning(" *** Warning: IRQ %d is unlikely to work! ***\n",
-                          dev->irq);
+               pr_warn(" *** Warning: IRQ %d is unlikely to work! ***\n",
+                       dev->irq);
 
        step = (window_read8(vp, 4, Wn4_NetDiag) & 0x1e) >> 1;
        if (print_info) {
@@ -1425,7 +1425,7 @@ static int vortex_probe1(struct device *gendev, void __iomem *ioaddr, int irq,
                }
                mii_preamble_required--;
                if (phy_idx == 0) {
-                       pr_warning("  ***WARNING*** No MII transceivers found!\n");
+                       pr_warn("  ***WARNING*** No MII transceivers found!\n");
                        vp->phys[0] = 24;
                } else {
                        vp->advertising = mdio_read(dev, vp->phys[0], MII_ADVERTISE);
@@ -1566,8 +1566,7 @@ vortex_up(struct net_device *dev)
                        pci_restore_state(VORTEX_PCI(vp));
                err = pci_enable_device(VORTEX_PCI(vp));
                if (err) {
-                       pr_warning("%s: Could not enable device\n",
-                               dev->name);
+                       pr_warn("%s: Could not enable device\n", dev->name);
                        goto err_out;
                }
        }
@@ -2007,8 +2006,8 @@ vortex_error(struct net_device *dev, int status)
                /* This occurs when we have the wrong media type! */
                if (DoneDidThat == 0  &&
                        ioread16(ioaddr + EL3_STATUS) & StatsFull) {
-                       pr_warning("%s: Updating statistics failed, disabling "
-                                  "stats as an interrupt source.\n", dev->name);
+                       pr_warn("%s: Updating statistics failed, disabling stats as an interrupt source\n",
+                               dev->name);
                        iowrite16(SetIntrEnb |
                                  (window_read16(vp, 5, 10) & ~StatsFull),
                                  ioaddr + EL3_CMD);
@@ -2147,8 +2146,8 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        if (vp->cur_tx - vp->dirty_tx >= TX_RING_SIZE) {
                if (vortex_debug > 0)
-                       pr_warning("%s: BUG! Tx Ring full, refusing to send buffer.\n",
-                                  dev->name);
+                       pr_warn("%s: BUG! Tx Ring full, refusing to send buffer\n",
+                               dev->name);
                netif_stop_queue(dev);
                return NETDEV_TX_BUSY;
        }
@@ -2177,10 +2176,10 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
 
                        vp->tx_ring[entry].frag[i+1].addr =
-                                       cpu_to_le32(pci_map_single(
-                                               VORTEX_PCI(vp),
-                                               (void *)skb_frag_address(frag),
-                                               skb_frag_size(frag), PCI_DMA_TODEVICE));
+                                       cpu_to_le32(skb_frag_dma_map(
+                                               &VORTEX_PCI(vp)->dev,
+                                               frag,
+                                               frag->page_offset, frag->size, DMA_TO_DEVICE));
 
                        if (i == skb_shinfo(skb)->nr_frags-1)
                                        vp->tx_ring[entry].frag[i+1].length = cpu_to_le32(skb_frag_size(frag)|LAST_FRAG);
@@ -2311,7 +2310,7 @@ vortex_interrupt(int irq, void *dev_id)
                }
 
                if (--work_done < 0) {
-                       pr_warning("%s: Too much work in interrupt, status %4.4x.\n",
+                       pr_warn("%s: Too much work in interrupt, status %4.4x\n",
                                dev->name, status);
                        /* Disable all pending interrupts. */
                        do {
@@ -2444,7 +2443,7 @@ boomerang_interrupt(int irq, void *dev_id)
                        vortex_error(dev, status);
 
                if (--work_done < 0) {
-                       pr_warning("%s: Too much work in interrupt, status %4.4x.\n",
+                       pr_warn("%s: Too much work in interrupt, status %4.4x\n",
                                dev->name, status);
                        /* Disable all pending interrupts. */
                        do {
@@ -2620,7 +2619,8 @@ boomerang_rx(struct net_device *dev)
                        if (skb == NULL) {
                                static unsigned long last_jif;
                                if (time_after(jiffies, last_jif + 10 * HZ)) {
-                                       pr_warning("%s: memory shortage\n", dev->name);
+                                       pr_warn("%s: memory shortage\n",
+                                               dev->name);
                                        last_jif = jiffies;
                                }
                                if ((vp->cur_rx - vp->dirty_rx) == RX_RING_SIZE)
@@ -2719,7 +2719,8 @@ vortex_close(struct net_device *dev)
        if (vp->rx_csumhits &&
            (vp->drv_flags & HAS_HWCKSM) == 0 &&
            (vp->card_idx >= MAX_UNITS || hw_checksums[vp->card_idx] == -1)) {
-               pr_warning("%s supports hardware checksums, and we're not using them!\n", dev->name);
+               pr_warn("%s supports hardware checksums, and we're not using them!\n",
+                       dev->name);
        }
 #endif
 
index 23578dfee249879064c1b86526ee80aead68b79f..3005155e412b2e0e1ab1d2c969e4895a2723644c 100644 (file)
@@ -123,6 +123,12 @@ static inline void greth_enable_tx(struct greth_private *greth)
        GRETH_REGORIN(greth->regs->control, GRETH_TXEN);
 }
 
+static inline void greth_enable_tx_and_irq(struct greth_private *greth)
+{
+       wmb(); /* BDs must been written to memory before enabling TX */
+       GRETH_REGORIN(greth->regs->control, GRETH_TXEN | GRETH_TXI);
+}
+
 static inline void greth_disable_tx(struct greth_private *greth)
 {
        GRETH_REGANDIN(greth->regs->control, ~GRETH_TXEN);
@@ -447,29 +453,30 @@ out:
        return err;
 }
 
+static inline u16 greth_num_free_bds(u16 tx_last, u16 tx_next)
+{
+       if (tx_next < tx_last)
+               return (tx_last - tx_next) - 1;
+       else
+               return GRETH_TXBD_NUM - (tx_next - tx_last) - 1;
+}
 
 static netdev_tx_t
 greth_start_xmit_gbit(struct sk_buff *skb, struct net_device *dev)
 {
        struct greth_private *greth = netdev_priv(dev);
        struct greth_bd *bdp;
-       u32 status = 0, dma_addr, ctrl;
+       u32 status, dma_addr;
        int curr_tx, nr_frags, i, err = NETDEV_TX_OK;
        unsigned long flags;
+       u16 tx_last;
 
        nr_frags = skb_shinfo(skb)->nr_frags;
+       tx_last = greth->tx_last;
+       rmb(); /* tx_last is updated by the poll task */
 
-       /* Clean TX Ring */
-       greth_clean_tx_gbit(dev);
-
-       if (greth->tx_free < nr_frags + 1) {
-               spin_lock_irqsave(&greth->devlock, flags);/*save from poll/irq*/
-               ctrl = GRETH_REGLOAD(greth->regs->control);
-               /* Enable TX IRQ only if not already in poll() routine */
-               if (ctrl & GRETH_RXI)
-                       GRETH_REGSAVE(greth->regs->control, ctrl | GRETH_TXI);
+       if (greth_num_free_bds(tx_last, greth->tx_next) < nr_frags + 1) {
                netif_stop_queue(dev);
-               spin_unlock_irqrestore(&greth->devlock, flags);
                err = NETDEV_TX_BUSY;
                goto out;
        }
@@ -488,6 +495,8 @@ greth_start_xmit_gbit(struct sk_buff *skb, struct net_device *dev)
        /* Linear buf */
        if (nr_frags != 0)
                status = GRETH_TXBD_MORE;
+       else
+               status = GRETH_BD_IE;
 
        if (skb->ip_summed == CHECKSUM_PARTIAL)
                status |= GRETH_TXBD_CSALL;
@@ -545,14 +554,12 @@ greth_start_xmit_gbit(struct sk_buff *skb, struct net_device *dev)
 
        /* Enable the descriptor chain by enabling the first descriptor */
        bdp = greth->tx_bd_base + greth->tx_next;
-       greth_write_bd(&bdp->stat, greth_read_bd(&bdp->stat) | GRETH_BD_EN);
-       greth->tx_next = curr_tx;
-       greth->tx_free -= nr_frags + 1;
-
-       wmb();
+       greth_write_bd(&bdp->stat,
+                      greth_read_bd(&bdp->stat) | GRETH_BD_EN);
 
        spin_lock_irqsave(&greth->devlock, flags); /*save from poll/irq*/
-       greth_enable_tx(greth);
+       greth->tx_next = curr_tx;
+       greth_enable_tx_and_irq(greth);
        spin_unlock_irqrestore(&greth->devlock, flags);
 
        return NETDEV_TX_OK;
@@ -648,7 +655,6 @@ static void greth_clean_tx(struct net_device *dev)
        if (greth->tx_free > 0) {
                netif_wake_queue(dev);
        }
-
 }
 
 static inline void greth_update_tx_stats(struct net_device *dev, u32 stat)
@@ -670,20 +676,22 @@ static void greth_clean_tx_gbit(struct net_device *dev)
 {
        struct greth_private *greth;
        struct greth_bd *bdp, *bdp_last_frag;
-       struct sk_buff *skb;
+       struct sk_buff *skb = NULL;
        u32 stat;
        int nr_frags, i;
+       u16 tx_last;
 
        greth = netdev_priv(dev);
+       tx_last = greth->tx_last;
 
-       while (greth->tx_free < GRETH_TXBD_NUM) {
+       while (tx_last != greth->tx_next) {
 
-               skb = greth->tx_skbuff[greth->tx_last];
+               skb = greth->tx_skbuff[tx_last];
 
                nr_frags = skb_shinfo(skb)->nr_frags;
 
                /* We only clean fully completed SKBs */
-               bdp_last_frag = greth->tx_bd_base + SKIP_TX(greth->tx_last, nr_frags);
+               bdp_last_frag = greth->tx_bd_base + SKIP_TX(tx_last, nr_frags);
 
                GRETH_REGSAVE(greth->regs->status, GRETH_INT_TE | GRETH_INT_TX);
                mb();
@@ -692,14 +700,14 @@ static void greth_clean_tx_gbit(struct net_device *dev)
                if (stat & GRETH_BD_EN)
                        break;
 
-               greth->tx_skbuff[greth->tx_last] = NULL;
+               greth->tx_skbuff[tx_last] = NULL;
 
                greth_update_tx_stats(dev, stat);
                dev->stats.tx_bytes += skb->len;
 
-               bdp = greth->tx_bd_base + greth->tx_last;
+               bdp = greth->tx_bd_base + tx_last;
 
-               greth->tx_last = NEXT_TX(greth->tx_last);
+               tx_last = NEXT_TX(tx_last);
 
                dma_unmap_single(greth->dev,
                                 greth_read_bd(&bdp->addr),
@@ -708,21 +716,26 @@ static void greth_clean_tx_gbit(struct net_device *dev)
 
                for (i = 0; i < nr_frags; i++) {
                        skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
-                       bdp = greth->tx_bd_base + greth->tx_last;
+                       bdp = greth->tx_bd_base + tx_last;
 
                        dma_unmap_page(greth->dev,
                                       greth_read_bd(&bdp->addr),
                                       skb_frag_size(frag),
                                       DMA_TO_DEVICE);
 
-                       greth->tx_last = NEXT_TX(greth->tx_last);
+                       tx_last = NEXT_TX(tx_last);
                }
-               greth->tx_free += nr_frags+1;
                dev_kfree_skb(skb);
        }
+       if (skb) { /* skb is set only if the above while loop was entered */
+               wmb();
+               greth->tx_last = tx_last;
 
-       if (netif_queue_stopped(dev) && (greth->tx_free > (MAX_SKB_FRAGS+1)))
-               netif_wake_queue(dev);
+               if (netif_queue_stopped(dev) &&
+                   (greth_num_free_bds(tx_last, greth->tx_next) >
+                   (MAX_SKB_FRAGS+1)))
+                       netif_wake_queue(dev);
+       }
 }
 
 static int greth_rx(struct net_device *dev, int limit)
@@ -965,16 +978,12 @@ static int greth_poll(struct napi_struct *napi, int budget)
        greth = container_of(napi, struct greth_private, napi);
 
 restart_txrx_poll:
-       if (netif_queue_stopped(greth->netdev)) {
-               if (greth->gbit_mac)
-                       greth_clean_tx_gbit(greth->netdev);
-               else
-                       greth_clean_tx(greth->netdev);
-       }
-
        if (greth->gbit_mac) {
+               greth_clean_tx_gbit(greth->netdev);
                work_done += greth_rx_gbit(greth->netdev, budget - work_done);
        } else {
+               if (netif_queue_stopped(greth->netdev))
+                       greth_clean_tx(greth->netdev);
                work_done += greth_rx(greth->netdev, budget - work_done);
        }
 
@@ -983,7 +992,8 @@ restart_txrx_poll:
                spin_lock_irqsave(&greth->devlock, flags);
 
                ctrl = GRETH_REGLOAD(greth->regs->control);
-               if (netif_queue_stopped(greth->netdev)) {
+               if ((greth->gbit_mac && (greth->tx_last != greth->tx_next)) ||
+                   (!greth->gbit_mac && netif_queue_stopped(greth->netdev))) {
                        GRETH_REGSAVE(greth->regs->control,
                                        ctrl | GRETH_TXI | GRETH_RXI);
                        mask = GRETH_INT_RX | GRETH_INT_RE |
index 232a622a85b7006ce8cb235f1d9790ea7b2c4929..ae16ac94daf825a5b800356603cb1c1213636d34 100644 (file)
@@ -107,7 +107,7 @@ struct greth_private {
 
        u16 tx_next;
        u16 tx_last;
-       u16 tx_free;
+       u16 tx_free; /* only used on 10/100Mbit */
        u16 rx_cur;
 
        struct greth_regs *regs;        /* Address of controller registers. */
index cc25a3a9e7cf388d6da509c7bfb7277d0f70549a..caade30820d50b9851228589a192f17bb8c9a915 100644 (file)
 #define DMA_PBL_X8_DISABLE             0x00
 #define DMA_PBL_X8_ENABLE              0x01
 
-
 /* MAC register offsets */
 #define MAC_TCR                                0x0000
 #define MAC_RCR                                0x0004
 #define MTL_Q_DISABLED                 0x00
 #define MTL_Q_ENABLED                  0x02
 
-
 /* MTL traffic class register offsets
  *   Multiple traffic classes can be active.  The first class has registers
  *   that begin at 0x1100.  Each subsequent queue has registers that
 #define MTL_TSA_SP                     0x00
 #define MTL_TSA_ETS                    0x02
 
-
 /* PCS MMD select register offset
  *  The MMD select register is used for accessing PCS registers
  *  when the underlying APB3 interface is using indirect addressing.
  */
 #define PCS_MMD_SELECT                 0xff
 
-
 /* Descriptor/Packet entry bit positions and sizes */
 #define RX_PACKET_ERRORS_CRC_INDEX             2
 #define RX_PACKET_ERRORS_CRC_WIDTH             1
 #define MDIO_AN_COMP_STAT              0x0030
 #endif
 
-
 /* Bit setting and getting macros
  *  The get macro will extract the current bit field value from within
  *  the variable
@@ -957,7 +952,6 @@ do {                                                                        \
                              ((0x1 << (_width)) - 1)) << (_index)));   \
 } while (0)
 
-
 /* Bit setting and getting macros based on register fields
  *  The get macro uses the bit field definitions formed using the input
  *  names to extract the current bit field value from within the
@@ -986,7 +980,6 @@ do {                                                                        \
                 _prefix##_##_field##_INDEX,                            \
                 _prefix##_##_field##_WIDTH, (_val))
 
-
 /* Macros for reading or writing registers
  *  The ioread macros will get bit fields or full values using the
  *  register definitions formed using the input names
@@ -1014,7 +1007,6 @@ do {                                                                      \
        XGMAC_IOWRITE((_pdata), _reg, reg_val);                         \
 } while (0)
 
-
 /* Macros for reading or writing MTL queue or traffic class registers
  *  Similar to the standard read and write macros except that the
  *  base register value is calculated by the queue or traffic class number
@@ -1041,7 +1033,6 @@ do {                                                                      \
        XGMAC_MTL_IOWRITE((_pdata), (_n), _reg, reg_val);               \
 } while (0)
 
-
 /* Macros for reading or writing DMA channel registers
  *  Similar to the standard read and write macros except that the
  *  base register value is obtained from the ring
@@ -1066,7 +1057,6 @@ do {                                                                      \
        XGMAC_DMA_IOWRITE((_channel), _reg, reg_val);                   \
 } while (0)
 
-
 /* Macros for building, reading or writing register values or bits
  * within the register values of XPCS registers.
  */
@@ -1076,7 +1066,6 @@ do {                                                                      \
 #define XPCS_IOREAD(_pdata, _off)                                      \
        ioread32((_pdata)->xpcs_regs + (_off))
 
-
 /* Macros for building, reading or writing register values or bits
  * using MDIO.  Different from above because of the use of standardized
  * Linux include values.  No shifting is performed with the bit
index 7d6a49b2432188665412ee2bdf44d58156cf51e9..8a50b01c2686292b06e97dae11c21c57095f6844 100644 (file)
 #include "xgbe.h"
 #include "xgbe-common.h"
 
-
 static int xgbe_dcb_ieee_getets(struct net_device *netdev,
                                struct ieee_ets *ets)
 {
index 346592dca33ce98dd94e24f33f99eabb373f60cb..76479d04b9037370ebb91cd161574c793eaf881b 100644 (file)
 #include "xgbe.h"
 #include "xgbe-common.h"
 
-
 static ssize_t xgbe_common_read(char __user *buffer, size_t count,
                                loff_t *ppos, unsigned int value)
 {
@@ -272,8 +271,8 @@ static ssize_t xpcs_reg_value_read(struct file *filp, char __user *buffer,
        struct xgbe_prv_data *pdata = filp->private_data;
        unsigned int value;
 
-       value = pdata->hw_if.read_mmd_regs(pdata, pdata->debugfs_xpcs_mmd,
-                                          pdata->debugfs_xpcs_reg);
+       value = XMDIO_READ(pdata, pdata->debugfs_xpcs_mmd,
+                          pdata->debugfs_xpcs_reg);
 
        return xgbe_common_read(buffer, count, ppos, value);
 }
@@ -290,8 +289,8 @@ static ssize_t xpcs_reg_value_write(struct file *filp,
        if (len < 0)
                return len;
 
-       pdata->hw_if.write_mmd_regs(pdata, pdata->debugfs_xpcs_mmd,
-                                   pdata->debugfs_xpcs_reg, value);
+       XMDIO_WRITE(pdata, pdata->debugfs_xpcs_mmd, pdata->debugfs_xpcs_reg,
+                   value);
 
        return len;
 }
index 1c5d62e8dab655013ea3883d983543ea7993a4b6..6fc5da01437d8ba75a3b8cf0cd16244b61e4f7d8 100644 (file)
 #include "xgbe.h"
 #include "xgbe-common.h"
 
-
 static void xgbe_unmap_skb(struct xgbe_prv_data *, struct xgbe_ring_data *);
 
 static void xgbe_free_ring(struct xgbe_prv_data *pdata,
@@ -524,11 +523,8 @@ static void xgbe_realloc_skb(struct xgbe_channel *channel)
 
                /* Allocate skb & assign to each rdesc */
                skb = dev_alloc_skb(pdata->rx_buf_size);
-               if (skb == NULL) {
-                       netdev_alert(pdata->netdev,
-                                    "failed to allocate skb\n");
+               if (skb == NULL)
                        break;
-               }
                skb_dma = dma_map_single(pdata->dev, skb->data,
                                         pdata->rx_buf_size, DMA_FROM_DEVICE);
                if (dma_mapping_error(pdata->dev, skb_dma)) {
index edaca4496264862063835a444594471df29658a2..9da3a03e8c0777595a7f99774be62c9528e55c6a 100644 (file)
 #include "xgbe.h"
 #include "xgbe-common.h"
 
-
 static unsigned int xgbe_usec_to_riwt(struct xgbe_prv_data *pdata,
                                      unsigned int usec)
 {
@@ -348,7 +347,7 @@ static int xgbe_disable_tx_flow_control(struct xgbe_prv_data *pdata)
 
        /* Clear MAC flow control */
        max_q_count = XGMAC_MAX_FLOW_CONTROL_QUEUES;
-       q_count = min_t(unsigned int, pdata->rx_q_count, max_q_count);
+       q_count = min_t(unsigned int, pdata->tx_q_count, max_q_count);
        reg = MAC_Q0TFCR;
        for (i = 0; i < q_count; i++) {
                reg_val = XGMAC_IOREAD(pdata, reg);
@@ -373,7 +372,7 @@ static int xgbe_enable_tx_flow_control(struct xgbe_prv_data *pdata)
 
        /* Set MAC flow control */
        max_q_count = XGMAC_MAX_FLOW_CONTROL_QUEUES;
-       q_count = min_t(unsigned int, pdata->rx_q_count, max_q_count);
+       q_count = min_t(unsigned int, pdata->tx_q_count, max_q_count);
        reg = MAC_Q0TFCR;
        for (i = 0; i < q_count; i++) {
                reg_val = XGMAC_IOREAD(pdata, reg);
@@ -509,8 +508,8 @@ static void xgbe_enable_mac_interrupts(struct xgbe_prv_data *pdata)
        XGMAC_IOWRITE(pdata, MAC_IER, mac_ier);
 
        /* Enable all counter interrupts */
-       XGMAC_IOWRITE_BITS(pdata, MMC_RIER, ALL_INTERRUPTS, 0xff);
-       XGMAC_IOWRITE_BITS(pdata, MMC_TIER, ALL_INTERRUPTS, 0xff);
+       XGMAC_IOWRITE_BITS(pdata, MMC_RIER, ALL_INTERRUPTS, 0xffffffff);
+       XGMAC_IOWRITE_BITS(pdata, MMC_TIER, ALL_INTERRUPTS, 0xffffffff);
 }
 
 static int xgbe_set_gmii_speed(struct xgbe_prv_data *pdata)
@@ -1633,6 +1632,9 @@ static int xgbe_flush_tx_queues(struct xgbe_prv_data *pdata)
 {
        unsigned int i, count;
 
+       if (XGMAC_GET_BITS(pdata->hw_feat.version, MAC_VR, SNPSVER) < 0x21)
+               return 0;
+
        for (i = 0; i < pdata->tx_q_count; i++)
                XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_TQOMR, FTQ, 1);
 
@@ -1703,8 +1705,8 @@ static void xgbe_config_mtl_mode(struct xgbe_prv_data *pdata)
        XGMAC_IOWRITE_BITS(pdata, MTL_OMR, RAA, MTL_RAA_SP);
 }
 
-static unsigned int xgbe_calculate_per_queue_fifo(unsigned long fifo_size,
-                                                 unsigned char queue_count)
+static unsigned int xgbe_calculate_per_queue_fifo(unsigned int fifo_size,
+                                                 unsigned int queue_count)
 {
        unsigned int q_fifo_size = 0;
        enum xgbe_mtl_fifo_size p_fifo = XGMAC_MTL_FIFO_SIZE_256;
@@ -1748,6 +1750,10 @@ static unsigned int xgbe_calculate_per_queue_fifo(unsigned long fifo_size,
                q_fifo_size = XGBE_FIFO_SIZE_KB(256);
                break;
        }
+
+       /* The configured value is not the actual amount of fifo RAM */
+       q_fifo_size = min_t(unsigned int, XGBE_FIFO_MAX, q_fifo_size);
+
        q_fifo_size = q_fifo_size / queue_count;
 
        /* Set the queue fifo size programmable value */
@@ -1947,6 +1953,32 @@ static void xgbe_config_vlan_support(struct xgbe_prv_data *pdata)
                xgbe_disable_rx_vlan_stripping(pdata);
 }
 
+static u64 xgbe_mmc_read(struct xgbe_prv_data *pdata, unsigned int reg_lo)
+{
+       bool read_hi;
+       u64 val;
+
+       switch (reg_lo) {
+       /* These registers are always 64 bit */
+       case MMC_TXOCTETCOUNT_GB_LO:
+       case MMC_TXOCTETCOUNT_G_LO:
+       case MMC_RXOCTETCOUNT_GB_LO:
+       case MMC_RXOCTETCOUNT_G_LO:
+               read_hi = true;
+               break;
+
+       default:
+               read_hi = false;
+       };
+
+       val = XGMAC_IOREAD(pdata, reg_lo);
+
+       if (read_hi)
+               val |= ((u64)XGMAC_IOREAD(pdata, reg_lo + 4) << 32);
+
+       return val;
+}
+
 static void xgbe_tx_mmc_int(struct xgbe_prv_data *pdata)
 {
        struct xgbe_mmc_stats *stats = &pdata->mmc_stats;
@@ -1954,75 +1986,75 @@ static void xgbe_tx_mmc_int(struct xgbe_prv_data *pdata)
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TXOCTETCOUNT_GB))
                stats->txoctetcount_gb +=
-                       XGMAC_IOREAD(pdata, MMC_TXOCTETCOUNT_GB_LO);
+                       xgbe_mmc_read(pdata, MMC_TXOCTETCOUNT_GB_LO);
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TXFRAMECOUNT_GB))
                stats->txframecount_gb +=
-                       XGMAC_IOREAD(pdata, MMC_TXFRAMECOUNT_GB_LO);
+                       xgbe_mmc_read(pdata, MMC_TXFRAMECOUNT_GB_LO);
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TXBROADCASTFRAMES_G))
                stats->txbroadcastframes_g +=
-                       XGMAC_IOREAD(pdata, MMC_TXBROADCASTFRAMES_G_LO);
+                       xgbe_mmc_read(pdata, MMC_TXBROADCASTFRAMES_G_LO);
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TXMULTICASTFRAMES_G))
                stats->txmulticastframes_g +=
-                       XGMAC_IOREAD(pdata, MMC_TXMULTICASTFRAMES_G_LO);
+                       xgbe_mmc_read(pdata, MMC_TXMULTICASTFRAMES_G_LO);
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TX64OCTETS_GB))
                stats->tx64octets_gb +=
-                       XGMAC_IOREAD(pdata, MMC_TX64OCTETS_GB_LO);
+                       xgbe_mmc_read(pdata, MMC_TX64OCTETS_GB_LO);
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TX65TO127OCTETS_GB))
                stats->tx65to127octets_gb +=
-                       XGMAC_IOREAD(pdata, MMC_TX65TO127OCTETS_GB_LO);
+                       xgbe_mmc_read(pdata, MMC_TX65TO127OCTETS_GB_LO);
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TX128TO255OCTETS_GB))
                stats->tx128to255octets_gb +=
-                       XGMAC_IOREAD(pdata, MMC_TX128TO255OCTETS_GB_LO);
+                       xgbe_mmc_read(pdata, MMC_TX128TO255OCTETS_GB_LO);
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TX256TO511OCTETS_GB))
                stats->tx256to511octets_gb +=
-                       XGMAC_IOREAD(pdata, MMC_TX256TO511OCTETS_GB_LO);
+                       xgbe_mmc_read(pdata, MMC_TX256TO511OCTETS_GB_LO);
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TX512TO1023OCTETS_GB))
                stats->tx512to1023octets_gb +=
-                       XGMAC_IOREAD(pdata, MMC_TX512TO1023OCTETS_GB_LO);
+                       xgbe_mmc_read(pdata, MMC_TX512TO1023OCTETS_GB_LO);
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TX1024TOMAXOCTETS_GB))
                stats->tx1024tomaxoctets_gb +=
-                       XGMAC_IOREAD(pdata, MMC_TX1024TOMAXOCTETS_GB_LO);
+                       xgbe_mmc_read(pdata, MMC_TX1024TOMAXOCTETS_GB_LO);
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TXUNICASTFRAMES_GB))
                stats->txunicastframes_gb +=
-                       XGMAC_IOREAD(pdata, MMC_TXUNICASTFRAMES_GB_LO);
+                       xgbe_mmc_read(pdata, MMC_TXUNICASTFRAMES_GB_LO);
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TXMULTICASTFRAMES_GB))
                stats->txmulticastframes_gb +=
-                       XGMAC_IOREAD(pdata, MMC_TXMULTICASTFRAMES_GB_LO);
+                       xgbe_mmc_read(pdata, MMC_TXMULTICASTFRAMES_GB_LO);
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TXBROADCASTFRAMES_GB))
                stats->txbroadcastframes_g +=
-                       XGMAC_IOREAD(pdata, MMC_TXBROADCASTFRAMES_GB_LO);
+                       xgbe_mmc_read(pdata, MMC_TXBROADCASTFRAMES_GB_LO);
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TXUNDERFLOWERROR))
                stats->txunderflowerror +=
-                       XGMAC_IOREAD(pdata, MMC_TXUNDERFLOWERROR_LO);
+                       xgbe_mmc_read(pdata, MMC_TXUNDERFLOWERROR_LO);
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TXOCTETCOUNT_G))
                stats->txoctetcount_g +=
-                       XGMAC_IOREAD(pdata, MMC_TXOCTETCOUNT_G_LO);
+                       xgbe_mmc_read(pdata, MMC_TXOCTETCOUNT_G_LO);
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TXFRAMECOUNT_G))
                stats->txframecount_g +=
-                       XGMAC_IOREAD(pdata, MMC_TXFRAMECOUNT_G_LO);
+                       xgbe_mmc_read(pdata, MMC_TXFRAMECOUNT_G_LO);
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TXPAUSEFRAMES))
                stats->txpauseframes +=
-                       XGMAC_IOREAD(pdata, MMC_TXPAUSEFRAMES_LO);
+                       xgbe_mmc_read(pdata, MMC_TXPAUSEFRAMES_LO);
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_TISR, TXVLANFRAMES_G))
                stats->txvlanframes_g +=
-                       XGMAC_IOREAD(pdata, MMC_TXVLANFRAMES_G_LO);
+                       xgbe_mmc_read(pdata, MMC_TXVLANFRAMES_G_LO);
 }
 
 static void xgbe_rx_mmc_int(struct xgbe_prv_data *pdata)
@@ -2032,95 +2064,95 @@ static void xgbe_rx_mmc_int(struct xgbe_prv_data *pdata)
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXFRAMECOUNT_GB))
                stats->rxframecount_gb +=
-                       XGMAC_IOREAD(pdata, MMC_RXFRAMECOUNT_GB_LO);
+                       xgbe_mmc_read(pdata, MMC_RXFRAMECOUNT_GB_LO);
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXOCTETCOUNT_GB))
                stats->rxoctetcount_gb +=
-                       XGMAC_IOREAD(pdata, MMC_RXOCTETCOUNT_GB_LO);
+                       xgbe_mmc_read(pdata, MMC_RXOCTETCOUNT_GB_LO);
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXOCTETCOUNT_G))
                stats->rxoctetcount_g +=
-                       XGMAC_IOREAD(pdata, MMC_RXOCTETCOUNT_G_LO);
+                       xgbe_mmc_read(pdata, MMC_RXOCTETCOUNT_G_LO);
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXBROADCASTFRAMES_G))
                stats->rxbroadcastframes_g +=
-                       XGMAC_IOREAD(pdata, MMC_RXBROADCASTFRAMES_G_LO);
+                       xgbe_mmc_read(pdata, MMC_RXBROADCASTFRAMES_G_LO);
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXMULTICASTFRAMES_G))
                stats->rxmulticastframes_g +=
-                       XGMAC_IOREAD(pdata, MMC_RXMULTICASTFRAMES_G_LO);
+                       xgbe_mmc_read(pdata, MMC_RXMULTICASTFRAMES_G_LO);
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXCRCERROR))
                stats->rxcrcerror +=
-                       XGMAC_IOREAD(pdata, MMC_RXCRCERROR_LO);
+                       xgbe_mmc_read(pdata, MMC_RXCRCERROR_LO);
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXRUNTERROR))
                stats->rxrunterror +=
-                       XGMAC_IOREAD(pdata, MMC_RXRUNTERROR);
+                       xgbe_mmc_read(pdata, MMC_RXRUNTERROR);
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXJABBERERROR))
                stats->rxjabbererror +=
-                       XGMAC_IOREAD(pdata, MMC_RXJABBERERROR);
+                       xgbe_mmc_read(pdata, MMC_RXJABBERERROR);
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXUNDERSIZE_G))
                stats->rxundersize_g +=
-                       XGMAC_IOREAD(pdata, MMC_RXUNDERSIZE_G);
+                       xgbe_mmc_read(pdata, MMC_RXUNDERSIZE_G);
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXOVERSIZE_G))
                stats->rxoversize_g +=
-                       XGMAC_IOREAD(pdata, MMC_RXOVERSIZE_G);
+                       xgbe_mmc_read(pdata, MMC_RXOVERSIZE_G);
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RX64OCTETS_GB))
                stats->rx64octets_gb +=
-                       XGMAC_IOREAD(pdata, MMC_RX64OCTETS_GB_LO);
+                       xgbe_mmc_read(pdata, MMC_RX64OCTETS_GB_LO);
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RX65TO127OCTETS_GB))
                stats->rx65to127octets_gb +=
-                       XGMAC_IOREAD(pdata, MMC_RX65TO127OCTETS_GB_LO);
+                       xgbe_mmc_read(pdata, MMC_RX65TO127OCTETS_GB_LO);
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RX128TO255OCTETS_GB))
                stats->rx128to255octets_gb +=
-                       XGMAC_IOREAD(pdata, MMC_RX128TO255OCTETS_GB_LO);
+                       xgbe_mmc_read(pdata, MMC_RX128TO255OCTETS_GB_LO);
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RX256TO511OCTETS_GB))
                stats->rx256to511octets_gb +=
-                       XGMAC_IOREAD(pdata, MMC_RX256TO511OCTETS_GB_LO);
+                       xgbe_mmc_read(pdata, MMC_RX256TO511OCTETS_GB_LO);
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RX512TO1023OCTETS_GB))
                stats->rx512to1023octets_gb +=
-                       XGMAC_IOREAD(pdata, MMC_RX512TO1023OCTETS_GB_LO);
+                       xgbe_mmc_read(pdata, MMC_RX512TO1023OCTETS_GB_LO);
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RX1024TOMAXOCTETS_GB))
                stats->rx1024tomaxoctets_gb +=
-                       XGMAC_IOREAD(pdata, MMC_RX1024TOMAXOCTETS_GB_LO);
+                       xgbe_mmc_read(pdata, MMC_RX1024TOMAXOCTETS_GB_LO);
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXUNICASTFRAMES_G))
                stats->rxunicastframes_g +=
-                       XGMAC_IOREAD(pdata, MMC_RXUNICASTFRAMES_G_LO);
+                       xgbe_mmc_read(pdata, MMC_RXUNICASTFRAMES_G_LO);
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXLENGTHERROR))
                stats->rxlengtherror +=
-                       XGMAC_IOREAD(pdata, MMC_RXLENGTHERROR_LO);
+                       xgbe_mmc_read(pdata, MMC_RXLENGTHERROR_LO);
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXOUTOFRANGETYPE))
                stats->rxoutofrangetype +=
-                       XGMAC_IOREAD(pdata, MMC_RXOUTOFRANGETYPE_LO);
+                       xgbe_mmc_read(pdata, MMC_RXOUTOFRANGETYPE_LO);
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXPAUSEFRAMES))
                stats->rxpauseframes +=
-                       XGMAC_IOREAD(pdata, MMC_RXPAUSEFRAMES_LO);
+                       xgbe_mmc_read(pdata, MMC_RXPAUSEFRAMES_LO);
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXFIFOOVERFLOW))
                stats->rxfifooverflow +=
-                       XGMAC_IOREAD(pdata, MMC_RXFIFOOVERFLOW_LO);
+                       xgbe_mmc_read(pdata, MMC_RXFIFOOVERFLOW_LO);
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXVLANFRAMES_GB))
                stats->rxvlanframes_gb +=
-                       XGMAC_IOREAD(pdata, MMC_RXVLANFRAMES_GB_LO);
+                       xgbe_mmc_read(pdata, MMC_RXVLANFRAMES_GB_LO);
 
        if (XGMAC_GET_BITS(mmc_isr, MMC_RISR, RXWATCHDOGERROR))
                stats->rxwatchdogerror +=
-                       XGMAC_IOREAD(pdata, MMC_RXWATCHDOGERROR);
+                       xgbe_mmc_read(pdata, MMC_RXWATCHDOGERROR);
 }
 
 static void xgbe_read_mmc_stats(struct xgbe_prv_data *pdata)
@@ -2131,127 +2163,127 @@ static void xgbe_read_mmc_stats(struct xgbe_prv_data *pdata)
        XGMAC_IOWRITE_BITS(pdata, MMC_CR, MCF, 1);
 
        stats->txoctetcount_gb +=
-               XGMAC_IOREAD(pdata, MMC_TXOCTETCOUNT_GB_LO);
+               xgbe_mmc_read(pdata, MMC_TXOCTETCOUNT_GB_LO);
 
        stats->txframecount_gb +=
-               XGMAC_IOREAD(pdata, MMC_TXFRAMECOUNT_GB_LO);
+               xgbe_mmc_read(pdata, MMC_TXFRAMECOUNT_GB_LO);
 
        stats->txbroadcastframes_g +=
-               XGMAC_IOREAD(pdata, MMC_TXBROADCASTFRAMES_G_LO);
+               xgbe_mmc_read(pdata, MMC_TXBROADCASTFRAMES_G_LO);
 
        stats->txmulticastframes_g +=
-               XGMAC_IOREAD(pdata, MMC_TXMULTICASTFRAMES_G_LO);
+               xgbe_mmc_read(pdata, MMC_TXMULTICASTFRAMES_G_LO);
 
        stats->tx64octets_gb +=
-               XGMAC_IOREAD(pdata, MMC_TX64OCTETS_GB_LO);
+               xgbe_mmc_read(pdata, MMC_TX64OCTETS_GB_LO);
 
        stats->tx65to127octets_gb +=
-               XGMAC_IOREAD(pdata, MMC_TX65TO127OCTETS_GB_LO);
+               xgbe_mmc_read(pdata, MMC_TX65TO127OCTETS_GB_LO);
 
        stats->tx128to255octets_gb +=
-               XGMAC_IOREAD(pdata, MMC_TX128TO255OCTETS_GB_LO);
+               xgbe_mmc_read(pdata, MMC_TX128TO255OCTETS_GB_LO);
 
        stats->tx256to511octets_gb +=
-               XGMAC_IOREAD(pdata, MMC_TX256TO511OCTETS_GB_LO);
+               xgbe_mmc_read(pdata, MMC_TX256TO511OCTETS_GB_LO);
 
        stats->tx512to1023octets_gb +=
-               XGMAC_IOREAD(pdata, MMC_TX512TO1023OCTETS_GB_LO);
+               xgbe_mmc_read(pdata, MMC_TX512TO1023OCTETS_GB_LO);
 
        stats->tx1024tomaxoctets_gb +=
-               XGMAC_IOREAD(pdata, MMC_TX1024TOMAXOCTETS_GB_LO);
+               xgbe_mmc_read(pdata, MMC_TX1024TOMAXOCTETS_GB_LO);
 
        stats->txunicastframes_gb +=
-               XGMAC_IOREAD(pdata, MMC_TXUNICASTFRAMES_GB_LO);
+               xgbe_mmc_read(pdata, MMC_TXUNICASTFRAMES_GB_LO);
 
        stats->txmulticastframes_gb +=
-               XGMAC_IOREAD(pdata, MMC_TXMULTICASTFRAMES_GB_LO);
+               xgbe_mmc_read(pdata, MMC_TXMULTICASTFRAMES_GB_LO);
 
        stats->txbroadcastframes_g +=
-               XGMAC_IOREAD(pdata, MMC_TXBROADCASTFRAMES_GB_LO);
+               xgbe_mmc_read(pdata, MMC_TXBROADCASTFRAMES_GB_LO);
 
        stats->txunderflowerror +=
-               XGMAC_IOREAD(pdata, MMC_TXUNDERFLOWERROR_LO);
+               xgbe_mmc_read(pdata, MMC_TXUNDERFLOWERROR_LO);
 
        stats->txoctetcount_g +=
-               XGMAC_IOREAD(pdata, MMC_TXOCTETCOUNT_G_LO);
+               xgbe_mmc_read(pdata, MMC_TXOCTETCOUNT_G_LO);
 
        stats->txframecount_g +=
-               XGMAC_IOREAD(pdata, MMC_TXFRAMECOUNT_G_LO);
+               xgbe_mmc_read(pdata, MMC_TXFRAMECOUNT_G_LO);
 
        stats->txpauseframes +=
-               XGMAC_IOREAD(pdata, MMC_TXPAUSEFRAMES_LO);
+               xgbe_mmc_read(pdata, MMC_TXPAUSEFRAMES_LO);
 
        stats->txvlanframes_g +=
-               XGMAC_IOREAD(pdata, MMC_TXVLANFRAMES_G_LO);
+               xgbe_mmc_read(pdata, MMC_TXVLANFRAMES_G_LO);
 
        stats->rxframecount_gb +=
-               XGMAC_IOREAD(pdata, MMC_RXFRAMECOUNT_GB_LO);
+               xgbe_mmc_read(pdata, MMC_RXFRAMECOUNT_GB_LO);
 
        stats->rxoctetcount_gb +=
-               XGMAC_IOREAD(pdata, MMC_RXOCTETCOUNT_GB_LO);
+               xgbe_mmc_read(pdata, MMC_RXOCTETCOUNT_GB_LO);
 
        stats->rxoctetcount_g +=
-               XGMAC_IOREAD(pdata, MMC_RXOCTETCOUNT_G_LO);
+               xgbe_mmc_read(pdata, MMC_RXOCTETCOUNT_G_LO);
 
        stats->rxbroadcastframes_g +=
-               XGMAC_IOREAD(pdata, MMC_RXBROADCASTFRAMES_G_LO);
+               xgbe_mmc_read(pdata, MMC_RXBROADCASTFRAMES_G_LO);
 
        stats->rxmulticastframes_g +=
-               XGMAC_IOREAD(pdata, MMC_RXMULTICASTFRAMES_G_LO);
+               xgbe_mmc_read(pdata, MMC_RXMULTICASTFRAMES_G_LO);
 
        stats->rxcrcerror +=
-               XGMAC_IOREAD(pdata, MMC_RXCRCERROR_LO);
+               xgbe_mmc_read(pdata, MMC_RXCRCERROR_LO);
 
        stats->rxrunterror +=
-               XGMAC_IOREAD(pdata, MMC_RXRUNTERROR);
+               xgbe_mmc_read(pdata, MMC_RXRUNTERROR);
 
        stats->rxjabbererror +=
-               XGMAC_IOREAD(pdata, MMC_RXJABBERERROR);
+               xgbe_mmc_read(pdata, MMC_RXJABBERERROR);
 
        stats->rxundersize_g +=
-               XGMAC_IOREAD(pdata, MMC_RXUNDERSIZE_G);
+               xgbe_mmc_read(pdata, MMC_RXUNDERSIZE_G);
 
        stats->rxoversize_g +=
-               XGMAC_IOREAD(pdata, MMC_RXOVERSIZE_G);
+               xgbe_mmc_read(pdata, MMC_RXOVERSIZE_G);
 
        stats->rx64octets_gb +=
-               XGMAC_IOREAD(pdata, MMC_RX64OCTETS_GB_LO);
+               xgbe_mmc_read(pdata, MMC_RX64OCTETS_GB_LO);
 
        stats->rx65to127octets_gb +=
-               XGMAC_IOREAD(pdata, MMC_RX65TO127OCTETS_GB_LO);
+               xgbe_mmc_read(pdata, MMC_RX65TO127OCTETS_GB_LO);
 
        stats->rx128to255octets_gb +=
-               XGMAC_IOREAD(pdata, MMC_RX128TO255OCTETS_GB_LO);
+               xgbe_mmc_read(pdata, MMC_RX128TO255OCTETS_GB_LO);
 
        stats->rx256to511octets_gb +=
-               XGMAC_IOREAD(pdata, MMC_RX256TO511OCTETS_GB_LO);
+               xgbe_mmc_read(pdata, MMC_RX256TO511OCTETS_GB_LO);
 
        stats->rx512to1023octets_gb +=
-               XGMAC_IOREAD(pdata, MMC_RX512TO1023OCTETS_GB_LO);
+               xgbe_mmc_read(pdata, MMC_RX512TO1023OCTETS_GB_LO);
 
        stats->rx1024tomaxoctets_gb +=
-               XGMAC_IOREAD(pdata, MMC_RX1024TOMAXOCTETS_GB_LO);
+               xgbe_mmc_read(pdata, MMC_RX1024TOMAXOCTETS_GB_LO);
 
        stats->rxunicastframes_g +=
-               XGMAC_IOREAD(pdata, MMC_RXUNICASTFRAMES_G_LO);
+               xgbe_mmc_read(pdata, MMC_RXUNICASTFRAMES_G_LO);
 
        stats->rxlengtherror +=
-               XGMAC_IOREAD(pdata, MMC_RXLENGTHERROR_LO);
+               xgbe_mmc_read(pdata, MMC_RXLENGTHERROR_LO);
 
        stats->rxoutofrangetype +=
-               XGMAC_IOREAD(pdata, MMC_RXOUTOFRANGETYPE_LO);
+               xgbe_mmc_read(pdata, MMC_RXOUTOFRANGETYPE_LO);
 
        stats->rxpauseframes +=
-               XGMAC_IOREAD(pdata, MMC_RXPAUSEFRAMES_LO);
+               xgbe_mmc_read(pdata, MMC_RXPAUSEFRAMES_LO);
 
        stats->rxfifooverflow +=
-               XGMAC_IOREAD(pdata, MMC_RXFIFOOVERFLOW_LO);
+               xgbe_mmc_read(pdata, MMC_RXFIFOOVERFLOW_LO);
 
        stats->rxvlanframes_gb +=
-               XGMAC_IOREAD(pdata, MMC_RXVLANFRAMES_GB_LO);
+               xgbe_mmc_read(pdata, MMC_RXVLANFRAMES_GB_LO);
 
        stats->rxwatchdogerror +=
-               XGMAC_IOREAD(pdata, MMC_RXWATCHDOGERROR);
+               xgbe_mmc_read(pdata, MMC_RXWATCHDOGERROR);
 
        /* Un-freeze counters */
        XGMAC_IOWRITE_BITS(pdata, MMC_CR, MCF, 0);
index dc84f7193c2db62aaf5d922f9beb409b13a975c3..29554992215aa18301f26b7e431b1fc19dfff9cb 100644 (file)
 #include "xgbe.h"
 #include "xgbe-common.h"
 
-
 static int xgbe_poll(struct napi_struct *, int);
 static void xgbe_set_rx_mode(struct net_device *);
 
@@ -361,6 +360,8 @@ void xgbe_get_all_hw_features(struct xgbe_prv_data *pdata)
 
        memset(hw_feat, 0, sizeof(*hw_feat));
 
+       hw_feat->version = XGMAC_IOREAD(pdata, MAC_VR);
+
        /* Hardware feature register 0 */
        hw_feat->gmii        = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, GMIISEL);
        hw_feat->vlhash      = XGMAC_GET_BITS(mac_hfr0, MAC_HWF0R, VLHASH);
index a076aca138a12ce4cdf69fb872d1d61c4202fbfa..49508ec98b72c1c01fdd189fc71e8c7465c77d2c 100644 (file)
 #include "xgbe.h"
 #include "xgbe-common.h"
 
-
 struct xgbe_stats {
        char stat_string[ETH_GSTRING_LEN];
        int stat_size;
@@ -173,6 +172,7 @@ static const struct xgbe_stats xgbe_gstring_stats[] = {
        XGMAC_MMC_STAT("rx_watchdog_errors", rxwatchdogerror),
        XGMAC_MMC_STAT("rx_pause_frames", rxpauseframes),
 };
+
 #define XGBE_STATS_COUNT       ARRAY_SIZE(xgbe_gstring_stats)
 
 static void xgbe_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
@@ -361,15 +361,16 @@ static void xgbe_get_drvinfo(struct net_device *netdev,
                             struct ethtool_drvinfo *drvinfo)
 {
        struct xgbe_prv_data *pdata = netdev_priv(netdev);
+       struct xgbe_hw_features *hw_feat = &pdata->hw_feat;
 
        strlcpy(drvinfo->driver, XGBE_DRV_NAME, sizeof(drvinfo->driver));
        strlcpy(drvinfo->version, XGBE_DRV_VERSION, sizeof(drvinfo->version));
        strlcpy(drvinfo->bus_info, dev_name(pdata->dev),
                sizeof(drvinfo->bus_info));
        snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), "%d.%d.%d",
-                XGMAC_IOREAD_BITS(pdata, MAC_VR, USERVER),
-                XGMAC_IOREAD_BITS(pdata, MAC_VR, DEVID),
-                XGMAC_IOREAD_BITS(pdata, MAC_VR, SNPSVER));
+                XGMAC_GET_BITS(hw_feat->version, MAC_VR, USERVER),
+                XGMAC_GET_BITS(hw_feat->version, MAC_VR, DEVID),
+                XGMAC_GET_BITS(hw_feat->version, MAC_VR, SNPSVER));
        drvinfo->n_stats = XGBE_STATS_COUNT;
 }
 
index 8aa6a9353f7bc5b5b3cf7592bc42186a93ca0bce..f5a8fa03921aafdff9dd8c8274b4bd055ad05e8c 100644 (file)
 #include "xgbe.h"
 #include "xgbe-common.h"
 
-
 MODULE_AUTHOR("Tom Lendacky <thomas.lendacky@amd.com>");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_VERSION(XGBE_DRV_VERSION);
@@ -172,7 +171,7 @@ static struct xgbe_channel *xgbe_alloc_rings(struct xgbe_prv_data *pdata)
                }
 
                if (i < pdata->rx_ring_count) {
-                       spin_lock_init(&tx_ring->lock);
+                       spin_lock_init(&rx_ring->lock);
                        channel->rx_ring = rx_ring++;
                }
 
index 6d2221e023f45a70ebdcb32f668f32b0e59b7671..363b210560f332e08837e9bfb9426dcea62707a4 100644 (file)
 #include "xgbe.h"
 #include "xgbe-common.h"
 
-
 static int xgbe_mdio_read(struct mii_bus *mii, int prtad, int mmd_reg)
 {
        struct xgbe_prv_data *pdata = mii->priv;
index 37e64cfa5718e6e45dc71d580296101327b7f49a..a1bf9d1cdae1e9d5dc666cf7b37f6320d1b2adff 100644 (file)
 #include "xgbe.h"
 #include "xgbe-common.h"
 
-
 static cycle_t xgbe_cc_read(const struct cyclecounter *cc)
 {
        struct xgbe_prv_data *pdata = container_of(cc,
index 07bf70a82908ead8e75b6e4704946ae10c961b37..789957d43a1379939e2aa9b8d15f267473a271a6 100644 (file)
 #include <linux/net_tstamp.h>
 #include <net/dcbnl.h>
 
-
 #define XGBE_DRV_NAME          "amd-xgbe"
 #define XGBE_DRV_VERSION       "1.0.0-a"
 #define XGBE_DRV_DESC          "AMD 10 Gigabit Ethernet Driver"
 #define XGMAC_DRIVER_CONTEXT   1
 #define XGMAC_IOCTL_CONTEXT    2
 
+#define XGBE_FIFO_MAX          81920
 #define XGBE_FIFO_SIZE_B(x)    (x)
 #define XGBE_FIFO_SIZE_KB(x)   (x * 1024)
 
        ((_ring)->rdata +                                       \
         ((_idx) & ((_ring)->rdesc_count - 1)))
 
-
 /* Default coalescing parameters */
 #define XGMAC_INIT_DMA_TX_USECS                50
 #define XGMAC_INIT_DMA_TX_FRAMES       25
@@ -526,6 +525,9 @@ struct xgbe_desc_if {
  * or configurations are present in the device.
  */
 struct xgbe_hw_features {
+       /* HW Version */
+       unsigned int version;
+
        /* HW Feature Register0 */
        unsigned int gmii;              /* 1000 Mbps support */
        unsigned int vlhash;            /* VLAN Hash Filter */
index 616dff6d3f5f3cc2837cdd9de776e943283a24fc..f4054d242f3c7ac6e52437c5cb795cac8e3da2dd 100644 (file)
@@ -1,5 +1,6 @@
 config NET_XGENE
        tristate "APM X-Gene SoC Ethernet Driver"
+       depends on HAS_DMA
        select PHYLIB
        help
          This is the Ethernet driver for the on-chip ethernet interface on the
index e1a8f4e19983ffe4f87139af1849906348648333..e4222af2baa66838d27d136c8e4c3d9be369679b 100644 (file)
@@ -563,15 +563,21 @@ static void xgene_enet_free_desc_rings(struct xgene_enet_pdata *pdata)
        struct xgene_enet_desc_ring *ring;
 
        ring = pdata->tx_ring;
-       if (ring && ring->cp_ring && ring->cp_ring->cp_skb)
-               devm_kfree(dev, ring->cp_ring->cp_skb);
-       xgene_enet_free_desc_ring(ring);
+       if (ring) {
+               if (ring->cp_ring && ring->cp_ring->cp_skb)
+                       devm_kfree(dev, ring->cp_ring->cp_skb);
+               xgene_enet_free_desc_ring(ring);
+       }
 
        ring = pdata->rx_ring;
-       if (ring && ring->buf_pool && ring->buf_pool->rx_skb)
-               devm_kfree(dev, ring->buf_pool->rx_skb);
-       xgene_enet_free_desc_ring(ring->buf_pool);
-       xgene_enet_free_desc_ring(ring);
+       if (ring) {
+               if (ring->buf_pool) {
+                       if (ring->buf_pool->rx_skb)
+                               devm_kfree(dev, ring->buf_pool->rx_skb);
+                       xgene_enet_free_desc_ring(ring->buf_pool);
+               }
+               xgene_enet_free_desc_ring(ring);
+       }
 }
 
 static struct xgene_enet_desc_ring *xgene_enet_create_desc_ring(
index 514c57fd26f1bbf6eda45da6c6e1aebdb735e37c..8e262e2b39b63fc5b1e26cca09c66c08b76169c9 100644 (file)
@@ -17,10 +17,14 @@ config NET_VENDOR_ARC
 
 if NET_VENDOR_ARC
 
-config ARC_EMAC
-       tristate "ARC EMAC support"
+config ARC_EMAC_CORE
+       tristate
        select MII
        select PHYLIB
+
+config ARC_EMAC
+       tristate "ARC EMAC support"
+       select ARC_EMAC_CORE
        depends on OF_IRQ
        depends on OF_NET
        ---help---
@@ -28,4 +32,14 @@ config ARC_EMAC
          non-standard on-chip ethernet device ARC EMAC 10/100 is used.
          Say Y here if you have such a board.  If unsure, say N.
 
+config EMAC_ROCKCHIP
+       tristate "Rockchip EMAC support"
+       select ARC_EMAC_CORE
+       depends on OF_IRQ && OF_NET && REGULATOR
+       ---help---
+         Support for Rockchip RK3066/RK3188 EMAC ethernet controllers.
+         This selects Rockchip SoC glue layer support for the
+         emac device driver. This driver is used for RK3066/RK3188
+         EMAC ethernet controller.
+
 endif # NET_VENDOR_ARC
index 00c8657637d56d8396d10d3edf3b298cd4efd298..79108af553fb8d9d6f4097a20b09b0372a1af505 100644 (file)
@@ -3,4 +3,6 @@
 #
 
 arc_emac-objs := emac_main.o emac_mdio.o
-obj-$(CONFIG_ARC_EMAC) += arc_emac.o
+obj-$(CONFIG_ARC_EMAC_CORE) += arc_emac.o
+obj-$(CONFIG_ARC_EMAC) += emac_arc.o
+obj-$(CONFIG_EMAC_ROCKCHIP) += emac_rockchip.o
index 36cc9bd07c478e7e776f7be199af0787eeb04da5..dae1ac300a49e692475a587381db629de3b4babc 100644 (file)
@@ -123,6 +123,10 @@ struct buffer_state {
  * @speed:     PHY's last set speed.
  */
 struct arc_emac_priv {
+       const char *drv_name;
+       const char *drv_version;
+       void (*set_mac_speed)(void *priv, unsigned int speed);
+
        /* Devices */
        struct device *dev;
        struct phy_device *phy_dev;
@@ -204,7 +208,9 @@ static inline void arc_reg_clr(struct arc_emac_priv *priv, int reg, int mask)
        arc_reg_set(priv, reg, value & ~mask);
 }
 
-int arc_mdio_probe(struct platform_device *pdev, struct arc_emac_priv *priv);
+int arc_mdio_probe(struct arc_emac_priv *priv);
 int arc_mdio_remove(struct arc_emac_priv *priv);
+int arc_emac_probe(struct net_device *ndev, int interface);
+int arc_emac_remove(struct net_device *ndev);
 
 #endif /* ARC_EMAC_H */
diff --git a/drivers/net/ethernet/arc/emac_arc.c b/drivers/net/ethernet/arc/emac_arc.c
new file mode 100644 (file)
index 0000000..f9cb99b
--- /dev/null
@@ -0,0 +1,95 @@
+/**
+ * emac_arc.c - ARC EMAC specific glue layer
+ *
+ * Copyright (C) 2014 Romain Perier
+ *
+ * Romain Perier  <romain.perier@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/module.h>
+#include <linux/of_net.h>
+#include <linux/platform_device.h>
+
+#include "emac.h"
+
+#define DRV_NAME    "emac_arc"
+#define DRV_VERSION "1.0"
+
+static int emac_arc_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct net_device *ndev;
+       struct arc_emac_priv *priv;
+       int interface, err;
+
+       if (!dev->of_node)
+               return -ENODEV;
+
+       ndev = alloc_etherdev(sizeof(struct arc_emac_priv));
+       if (!ndev)
+               return -ENOMEM;
+       platform_set_drvdata(pdev, ndev);
+       SET_NETDEV_DEV(ndev, dev);
+
+       priv = netdev_priv(ndev);
+       priv->drv_name = DRV_NAME;
+       priv->drv_version = DRV_VERSION;
+
+       interface = of_get_phy_mode(dev->of_node);
+       if (interface < 0)
+               interface = PHY_INTERFACE_MODE_MII;
+
+       priv->clk = devm_clk_get(dev, "hclk");
+       if (IS_ERR(priv->clk)) {
+               dev_err(dev, "failed to retrieve host clock from device tree\n");
+               err = -EINVAL;
+               goto out_netdev;
+       }
+
+       err = arc_emac_probe(ndev, interface);
+out_netdev:
+       if (err)
+               free_netdev(ndev);
+       return err;
+}
+
+static int emac_arc_remove(struct platform_device *pdev)
+{
+       struct net_device *ndev = platform_get_drvdata(pdev);
+       int err;
+
+       err = arc_emac_remove(ndev);
+       free_netdev(ndev);
+       return err;
+}
+
+static const struct of_device_id emac_arc_dt_ids[] = {
+       { .compatible = "snps,arc-emac" },
+       { /* Sentinel */ }
+};
+
+static struct platform_driver emac_arc_driver = {
+       .probe = emac_arc_probe,
+       .remove = emac_arc_remove,
+       .driver = {
+               .name = DRV_NAME,
+               .of_match_table  = emac_arc_dt_ids,
+       },
+};
+
+module_platform_driver(emac_arc_driver);
+
+MODULE_AUTHOR("Romain Perier <romain.perier@gmail.com>");
+MODULE_DESCRIPTION("ARC EMAC platform driver");
+MODULE_LICENSE("GPL");
index fe5cfeace6e3e1cd5bdcbce922b5b51e0f7cc326..dbea8472bfb47ab6293d2cb9277b342c15ccaff6 100644 (file)
@@ -26,8 +26,6 @@
 
 #include "emac.h"
 
-#define DRV_NAME       "arc_emac"
-#define DRV_VERSION    "1.0"
 
 /**
  * arc_emac_adjust_link - Adjust the PHY link duplex.
@@ -50,6 +48,8 @@ static void arc_emac_adjust_link(struct net_device *ndev)
        if (priv->speed != phy_dev->speed) {
                priv->speed = phy_dev->speed;
                state_changed = 1;
+               if (priv->set_mac_speed)
+                       priv->set_mac_speed(priv, priv->speed);
        }
 
        if (priv->duplex != phy_dev->duplex) {
@@ -120,8 +120,10 @@ static int arc_emac_set_settings(struct net_device *ndev,
 static void arc_emac_get_drvinfo(struct net_device *ndev,
                                 struct ethtool_drvinfo *info)
 {
-       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
-       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       struct arc_emac_priv *priv = netdev_priv(ndev);
+
+       strlcpy(info->driver, priv->drv_name, sizeof(info->driver));
+       strlcpy(info->version, priv->drv_version, sizeof(info->version));
 }
 
 static const struct ethtool_ops arc_emac_ethtool_ops = {
@@ -671,46 +673,38 @@ static const struct net_device_ops arc_emac_netdev_ops = {
 #endif
 };
 
-static int arc_emac_probe(struct platform_device *pdev)
+int arc_emac_probe(struct net_device *ndev, int interface)
 {
+       struct device *dev = ndev->dev.parent;
        struct resource res_regs;
        struct device_node *phy_node;
        struct arc_emac_priv *priv;
-       struct net_device *ndev;
        const char *mac_addr;
        unsigned int id, clock_frequency, irq;
        int err;
 
-       if (!pdev->dev.of_node)
-               return -ENODEV;
 
        /* Get PHY from device tree */
-       phy_node = of_parse_phandle(pdev->dev.of_node, "phy", 0);
+       phy_node = of_parse_phandle(dev->of_node, "phy", 0);
        if (!phy_node) {
-               dev_err(&pdev->dev, "failed to retrieve phy description from device tree\n");
+               dev_err(dev, "failed to retrieve phy description from device tree\n");
                return -ENODEV;
        }
 
        /* Get EMAC registers base address from device tree */
-       err = of_address_to_resource(pdev->dev.of_node, 0, &res_regs);
+       err = of_address_to_resource(dev->of_node, 0, &res_regs);
        if (err) {
-               dev_err(&pdev->dev, "failed to retrieve registers base from device tree\n");
+               dev_err(dev, "failed to retrieve registers base from device tree\n");
                return -ENODEV;
        }
 
        /* Get IRQ from device tree */
-       irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
+       irq = irq_of_parse_and_map(dev->of_node, 0);
        if (!irq) {
-               dev_err(&pdev->dev, "failed to retrieve <irq> value from device tree\n");
+               dev_err(dev, "failed to retrieve <irq> value from device tree\n");
                return -ENODEV;
        }
 
-       ndev = alloc_etherdev(sizeof(struct arc_emac_priv));
-       if (!ndev)
-               return -ENOMEM;
-
-       platform_set_drvdata(pdev, ndev);
-       SET_NETDEV_DEV(ndev, &pdev->dev);
 
        ndev->netdev_ops = &arc_emac_netdev_ops;
        ndev->ethtool_ops = &arc_emac_ethtool_ops;
@@ -719,60 +713,57 @@ static int arc_emac_probe(struct platform_device *pdev)
        ndev->flags &= ~IFF_MULTICAST;
 
        priv = netdev_priv(ndev);
-       priv->dev = &pdev->dev;
+       priv->dev = dev;
 
-       priv->regs = devm_ioremap_resource(&pdev->dev, &res_regs);
+       priv->regs = devm_ioremap_resource(dev, &res_regs);
        if (IS_ERR(priv->regs)) {
-               err = PTR_ERR(priv->regs);
-               goto out_netdev;
+               return PTR_ERR(priv->regs);
        }
-       dev_dbg(&pdev->dev, "Registers base address is 0x%p\n", priv->regs);
+       dev_dbg(dev, "Registers base address is 0x%p\n", priv->regs);
 
-       priv->clk = of_clk_get(pdev->dev.of_node, 0);
-       if (IS_ERR(priv->clk)) {
-               /* Get CPU clock frequency from device tree */
-               if (of_property_read_u32(pdev->dev.of_node, "clock-frequency",
-                                       &clock_frequency)) {
-                       dev_err(&pdev->dev, "failed to retrieve <clock-frequency> from device tree\n");
-                       err = -EINVAL;
-                       goto out_netdev;
-               }
-       } else {
+       if (priv->clk) {
                err = clk_prepare_enable(priv->clk);
                if (err) {
-                       dev_err(&pdev->dev, "failed to enable clock\n");
-                       goto out_clkget;
+                       dev_err(dev, "failed to enable clock\n");
+                       return err;
                }
 
                clock_frequency = clk_get_rate(priv->clk);
+       } else {
+               /* Get CPU clock frequency from device tree */
+               if (of_property_read_u32(dev->of_node, "clock-frequency",
+                                        &clock_frequency)) {
+                       dev_err(dev, "failed to retrieve <clock-frequency> from device tree\n");
+                       return -EINVAL;
+               }
        }
 
        id = arc_reg_get(priv, R_ID);
 
        /* Check for EMAC revision 5 or 7, magic number */
        if (!(id == 0x0005fd02 || id == 0x0007fd02)) {
-               dev_err(&pdev->dev, "ARC EMAC not detected, id=0x%x\n", id);
+               dev_err(dev, "ARC EMAC not detected, id=0x%x\n", id);
                err = -ENODEV;
                goto out_clken;
        }
-       dev_info(&pdev->dev, "ARC EMAC detected with id: 0x%x\n", id);
+       dev_info(dev, "ARC EMAC detected with id: 0x%x\n", id);
 
        /* Set poll rate so that it polls every 1 ms */
        arc_reg_set(priv, R_POLLRATE, clock_frequency / 1000000);
 
        ndev->irq = irq;
-       dev_info(&pdev->dev, "IRQ is %d\n", ndev->irq);
+       dev_info(dev, "IRQ is %d\n", ndev->irq);
 
        /* Register interrupt handler for device */
-       err = devm_request_irq(&pdev->dev, ndev->irq, arc_emac_intr, 0,
+       err = devm_request_irq(dev, ndev->irq, arc_emac_intr, 0,
                               ndev->name, ndev);
        if (err) {
-               dev_err(&pdev->dev, "could not allocate IRQ\n");
+               dev_err(dev, "could not allocate IRQ\n");
                goto out_clken;
        }
 
        /* Get MAC address from device tree */
-       mac_addr = of_get_mac_address(pdev->dev.of_node);
+       mac_addr = of_get_mac_address(dev->of_node);
 
        if (mac_addr)
                memcpy(ndev->dev_addr, mac_addr, ETH_ALEN);
@@ -780,14 +771,14 @@ static int arc_emac_probe(struct platform_device *pdev)
                eth_hw_addr_random(ndev);
 
        arc_emac_set_address_internal(ndev);
-       dev_info(&pdev->dev, "MAC address is now %pM\n", ndev->dev_addr);
+       dev_info(dev, "MAC address is now %pM\n", ndev->dev_addr);
 
        /* Do 1 allocation instead of 2 separate ones for Rx and Tx BD rings */
-       priv->rxbd = dmam_alloc_coherent(&pdev->dev, RX_RING_SZ + TX_RING_SZ,
+       priv->rxbd = dmam_alloc_coherent(dev, RX_RING_SZ + TX_RING_SZ,
                                         &priv->rxbd_dma, GFP_KERNEL);
 
        if (!priv->rxbd) {
-               dev_err(&pdev->dev, "failed to allocate data buffers\n");
+               dev_err(dev, "failed to allocate data buffers\n");
                err = -ENOMEM;
                goto out_clken;
        }
@@ -795,31 +786,31 @@ static int arc_emac_probe(struct platform_device *pdev)
        priv->txbd = priv->rxbd + RX_BD_NUM;
 
        priv->txbd_dma = priv->rxbd_dma + RX_RING_SZ;
-       dev_dbg(&pdev->dev, "EMAC Device addr: Rx Ring [0x%x], Tx Ring[%x]\n",
+       dev_dbg(dev, "EMAC Device addr: Rx Ring [0x%x], Tx Ring[%x]\n",
                (unsigned int)priv->rxbd_dma, (unsigned int)priv->txbd_dma);
 
-       err = arc_mdio_probe(pdev, priv);
+       err = arc_mdio_probe(priv);
        if (err) {
-               dev_err(&pdev->dev, "failed to probe MII bus\n");
+               dev_err(dev, "failed to probe MII bus\n");
                goto out_clken;
        }
 
        priv->phy_dev = of_phy_connect(ndev, phy_node, arc_emac_adjust_link, 0,
-                                      PHY_INTERFACE_MODE_MII);
+                                      interface);
        if (!priv->phy_dev) {
-               dev_err(&pdev->dev, "of_phy_connect() failed\n");
+               dev_err(dev, "of_phy_connect() failed\n");
                err = -ENODEV;
                goto out_mdio;
        }
 
-       dev_info(&pdev->dev, "connected to %s phy with id 0x%x\n",
+       dev_info(dev, "connected to %s phy with id 0x%x\n",
                 priv->phy_dev->drv->name, priv->phy_dev->phy_id);
 
        netif_napi_add(ndev, &priv->napi, arc_emac_poll, ARC_EMAC_NAPI_WEIGHT);
 
        err = register_netdev(ndev);
        if (err) {
-               dev_err(&pdev->dev, "failed to register network device\n");
+               dev_err(dev, "failed to register network device\n");
                goto out_netif_api;
        }
 
@@ -832,19 +823,14 @@ out_netif_api:
 out_mdio:
        arc_mdio_remove(priv);
 out_clken:
-       if (!IS_ERR(priv->clk))
+       if (priv->clk)
                clk_disable_unprepare(priv->clk);
-out_clkget:
-       if (!IS_ERR(priv->clk))
-               clk_put(priv->clk);
-out_netdev:
-       free_netdev(ndev);
        return err;
 }
+EXPORT_SYMBOL_GPL(arc_emac_probe);
 
-static int arc_emac_remove(struct platform_device *pdev)
+int arc_emac_remove(struct net_device *ndev)
 {
-       struct net_device *ndev = platform_get_drvdata(pdev);
        struct arc_emac_priv *priv = netdev_priv(ndev);
 
        phy_disconnect(priv->phy_dev);
@@ -855,31 +841,12 @@ static int arc_emac_remove(struct platform_device *pdev)
 
        if (!IS_ERR(priv->clk)) {
                clk_disable_unprepare(priv->clk);
-               clk_put(priv->clk);
        }
 
-       free_netdev(ndev);
 
        return 0;
 }
-
-static const struct of_device_id arc_emac_dt_ids[] = {
-       { .compatible = "snps,arc-emac" },
-       { /* Sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, arc_emac_dt_ids);
-
-static struct platform_driver arc_emac_driver = {
-       .probe = arc_emac_probe,
-       .remove = arc_emac_remove,
-       .driver = {
-               .name = DRV_NAME,
-               .owner = THIS_MODULE,
-               .of_match_table  = arc_emac_dt_ids,
-               },
-};
-
-module_platform_driver(arc_emac_driver);
+EXPORT_SYMBOL_GPL(arc_emac_remove);
 
 MODULE_AUTHOR("Alexey Brodkin <abrodkin@synopsys.com>");
 MODULE_DESCRIPTION("ARC EMAC driver");
index 26ba2423f33a9a383b79c6a58d37e07b3d456cd3..d5ee986936dadd6764a0fe08ecc3b963c2e97d88 100644 (file)
@@ -100,7 +100,6 @@ static int arc_mdio_write(struct mii_bus *bus, int phy_addr,
 
 /**
  * arc_mdio_probe - MDIO probe function.
- * @pdev:      Pointer to platform device.
  * @priv:      Pointer to ARC EMAC private data structure.
  *
  * returns:    0 on success, -ENOMEM when mdiobus_alloc
@@ -108,7 +107,7 @@ static int arc_mdio_write(struct mii_bus *bus, int phy_addr,
  *
  * Sets up and registers the MDIO interface.
  */
-int arc_mdio_probe(struct platform_device *pdev, struct arc_emac_priv *priv)
+int arc_mdio_probe(struct arc_emac_priv *priv)
 {
        struct mii_bus *bus;
        int error;
@@ -124,9 +123,9 @@ int arc_mdio_probe(struct platform_device *pdev, struct arc_emac_priv *priv)
        bus->read = &arc_mdio_read;
        bus->write = &arc_mdio_write;
 
-       snprintf(bus->id, MII_BUS_ID_SIZE, "%s", pdev->name);
+       snprintf(bus->id, MII_BUS_ID_SIZE, "%s", bus->name);
 
-       error = of_mdiobus_register(bus, pdev->dev.of_node);
+       error = of_mdiobus_register(bus, priv->dev->of_node);
        if (error) {
                dev_err(priv->dev, "cannot register MDIO bus %s\n", bus->name);
                mdiobus_free(bus);
diff --git a/drivers/net/ethernet/arc/emac_rockchip.c b/drivers/net/ethernet/arc/emac_rockchip.c
new file mode 100644 (file)
index 0000000..51d0585
--- /dev/null
@@ -0,0 +1,228 @@
+/**
+ * emac-rockchip.c - Rockchip EMAC specific glue layer
+ *
+ * Copyright (C) 2014 Romain Perier <romain.perier@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_net.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+
+#include "emac.h"
+
+#define DRV_NAME        "rockchip_emac"
+#define DRV_VERSION     "1.0"
+
+#define GRF_MODE_MII           (1UL << 0)
+#define GRF_MODE_RMII          (0UL << 0)
+#define GRF_SPEED_10M          (0UL << 1)
+#define GRF_SPEED_100M         (1UL << 1)
+#define GRF_SPEED_ENABLE_BIT   (1UL << 17)
+#define GRF_MODE_ENABLE_BIT    (1UL << 16)
+
+struct emac_rockchip_soc_data {
+       int grf_offset;
+};
+
+struct rockchip_priv_data {
+       struct arc_emac_priv emac;
+       struct regmap *grf;
+       const struct emac_rockchip_soc_data *soc_data;
+       struct regulator *regulator;
+       struct clk *refclk;
+};
+
+static void emac_rockchip_set_mac_speed(void *priv, unsigned int speed)
+{
+       struct rockchip_priv_data *emac = priv;
+       u32 data;
+       int err = 0;
+
+       /* write-enable bits */
+       data = GRF_SPEED_ENABLE_BIT;
+
+       switch(speed) {
+       case 10:
+               data |= GRF_SPEED_10M;
+               break;
+       case 100:
+               data |= GRF_SPEED_100M;
+               break;
+       default:
+               pr_err("speed %u not supported\n", speed);
+               return;
+       }
+
+       err = regmap_write(emac->grf, emac->soc_data->grf_offset, data);
+       if (err)
+               pr_err("unable to apply speed %u to grf (%d)\n", speed, err);
+}
+
+static const struct emac_rockchip_soc_data emac_rockchip_dt_data[] = {
+       { .grf_offset = 0x154 }, /* rk3066 */
+       { .grf_offset = 0x0a4 }, /* rk3188 */
+};
+
+static const struct of_device_id emac_rockchip_dt_ids[] = {
+       { .compatible = "rockchip,rk3066-emac", .data = &emac_rockchip_dt_data[0] },
+       { .compatible = "rockchip,rk3188-emac", .data = &emac_rockchip_dt_data[1] },
+       { /* Sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, emac_rockchip_dt_ids);
+
+static int emac_rockchip_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct net_device *ndev;
+       struct rockchip_priv_data *priv;
+       const struct of_device_id *match;
+       u32 data;
+       int err, interface;
+
+       if (!pdev->dev.of_node)
+               return -ENODEV;
+
+       ndev = alloc_etherdev(sizeof(struct rockchip_priv_data));
+       if (!ndev)
+               return -ENOMEM;
+       platform_set_drvdata(pdev, ndev);
+       SET_NETDEV_DEV(ndev, dev);
+
+       priv = netdev_priv(ndev);
+       priv->emac.drv_name = DRV_NAME;
+       priv->emac.drv_version = DRV_VERSION;
+       priv->emac.set_mac_speed = emac_rockchip_set_mac_speed;
+
+       interface = of_get_phy_mode(dev->of_node);
+
+       /* RK3066 and RK3188 SoCs only support RMII */
+       if (interface != PHY_INTERFACE_MODE_RMII) {
+               dev_err(dev, "unsupported phy interface mode %d\n", interface);
+               err = -ENOTSUPP;
+               goto out_netdev;
+       }
+
+       priv->grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf");
+       if (IS_ERR(priv->grf)) {
+               dev_err(dev, "failed to retrieve global register file (%ld)\n", PTR_ERR(priv->grf));
+               err = PTR_ERR(priv->grf);
+               goto out_netdev;
+       }
+
+       match = of_match_node(emac_rockchip_dt_ids, dev->of_node);
+       priv->soc_data = match->data;
+
+       priv->emac.clk = devm_clk_get(dev, "hclk");
+       if (IS_ERR(priv->emac.clk)) {
+               dev_err(dev, "failed to retrieve host clock (%ld)\n", PTR_ERR(priv->emac.clk));
+               err = PTR_ERR(priv->emac.clk);
+               goto out_netdev;
+       }
+
+       priv->refclk = devm_clk_get(dev, "macref");
+       if (IS_ERR(priv->refclk)) {
+               dev_err(dev, "failed to retrieve reference clock (%ld)\n", PTR_ERR(priv->refclk));
+               err = PTR_ERR(priv->refclk);
+               goto out_netdev;
+       }
+
+       err = clk_prepare_enable(priv->refclk);
+       if (err) {
+               dev_err(dev, "failed to enable reference clock (%d)\n", err);
+               goto out_netdev;
+       }
+
+       /* Optional regulator for PHY */
+       priv->regulator = devm_regulator_get_optional(dev, "phy");
+       if (IS_ERR(priv->regulator)) {
+               if (PTR_ERR(priv->regulator) == -EPROBE_DEFER)
+                       return -EPROBE_DEFER;
+               dev_err(dev, "no regulator found\n");
+               priv->regulator = NULL;
+       }
+
+       if (priv->regulator) {
+               err = regulator_enable(priv->regulator);
+               if (err) {
+                       dev_err(dev, "failed to enable phy-supply (%d)\n", err);
+                       goto out_clk_disable;
+               }
+       }
+
+       err = arc_emac_probe(ndev, interface);
+       if (err)
+               goto out_regulator_disable;
+
+       /* write-enable bits */
+       data = GRF_MODE_ENABLE_BIT | GRF_SPEED_ENABLE_BIT;
+
+       data |= GRF_SPEED_100M;
+       data |= GRF_MODE_RMII;
+
+       err = regmap_write(priv->grf, priv->soc_data->grf_offset, data);
+       if (err) {
+               dev_err(dev, "unable to apply initial settings to grf (%d)\n", err);
+               goto out_regulator_disable;
+       }
+
+       /* RMII interface needs always a rate of 50MHz */
+       err = clk_set_rate(priv->refclk, 50000000);
+       if (err)
+               dev_err(dev, "failed to change reference clock rate (%d)\n", err);
+       return 0;
+
+out_regulator_disable:
+       if (priv->regulator)
+               regulator_disable(priv->regulator);
+out_clk_disable:
+       clk_disable_unprepare(priv->refclk);
+out_netdev:
+       free_netdev(ndev);
+       return err;
+}
+
+static int emac_rockchip_remove(struct platform_device *pdev)
+{
+       struct net_device *ndev = platform_get_drvdata(pdev);
+       struct rockchip_priv_data *priv = netdev_priv(ndev);
+       int err;
+
+       clk_disable_unprepare(priv->refclk);
+
+       if (priv->regulator)
+               regulator_disable(priv->regulator);
+
+       err = arc_emac_remove(ndev);
+       free_netdev(ndev);
+       return err;
+}
+
+static struct platform_driver emac_rockchip_driver = {
+       .probe = emac_rockchip_probe,
+       .remove = emac_rockchip_remove,
+       .driver = {
+               .name = DRV_NAME,
+               .of_match_table  = emac_rockchip_dt_ids,
+       },
+};
+
+module_platform_driver(emac_rockchip_driver);
+
+MODULE_AUTHOR("Romain Perier <romain.perier@gmail.com>");
+MODULE_DESCRIPTION("Rockchip EMAC platform driver");
+MODULE_LICENSE("GPL");
index 7dcfb19a31c888894121aa03c83bc8fe439bc4cf..c3e260c21734c37ca1641ffbf9441c867d18deb6 100644 (file)
@@ -84,7 +84,7 @@ config BNX2
 
 config CNIC
        tristate "QLogic CNIC support"
-       depends on PCI
+       depends on PCI && (IPV6 || IPV6=n)
        select BNX2
        select UIO
        ---help---
@@ -122,6 +122,7 @@ config TIGON3
 config BNX2X
        tristate "Broadcom NetXtremeII 10Gb support"
        depends on PCI
+       select PTP_1588_CLOCK
        select FW_LOADER
        select ZLIB_INFLATE
        select LIBCRC32C
index 4a7028d6591287a4e0bd3a03ee339528d05e1f98..56fadbd4258ac7cdbe96595f456c6fb2f0735037 100644 (file)
@@ -427,7 +427,7 @@ static void b44_wap54g10_workaround(struct b44 *bp)
        }
        return;
 error:
-       pr_warning("PHY: cannot reset MII transceiver isolate bit\n");
+       pr_warn("PHY: cannot reset MII transceiver isolate bit\n");
 }
 #else
 static inline void b44_wap54g10_workaround(struct b44 *bp)
index 6f4e18644bd4e5089c7485acd7417a0adff76bff..662cf222287350aea861f794668e41311d301388 100644 (file)
@@ -139,6 +139,15 @@ static int bcm_sysport_set_rx_csum(struct net_device *dev,
        else
                reg &= ~RXCHK_SKIP_FCS;
 
+       /* If Broadcom tags are enabled (e.g: using a switch), make
+        * sure we tell the RXCHK hardware to expect a 4-bytes Broadcom
+        * tag after the Ethernet MAC Source Address.
+        */
+       if (netdev_uses_dsa(dev))
+               reg |= RXCHK_BRCM_TAG_EN;
+       else
+               reg &= ~RXCHK_BRCM_TAG_EN;
+
        rxchk_writel(priv, reg, RXCHK_CONTROL);
 
        return 0;
@@ -1062,16 +1071,19 @@ static void bcm_sysport_adj_link(struct net_device *dev)
        if (!phydev->pause)
                cmd_bits |= CMD_RX_PAUSE_IGNORE | CMD_TX_PAUSE_IGNORE;
 
-       if (changed) {
+       if (!changed)
+               return;
+
+       if (phydev->link) {
                reg = 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;
                umac_writel(priv, reg, UMAC_CMD);
-
-               phy_print_status(priv->phydev);
        }
+
+       phy_print_status(priv->phydev);
 }
 
 static int bcm_sysport_init_tx_ring(struct bcm_sysport_priv *priv,
index d777fae869883fedd4ecba03987f8b56e3db56cb..86e94517a536fcdf75d38673cd4f7c17895836e5 100644 (file)
 #include <linux/types.h>
 #include <linux/pci_regs.h>
 
+#include <linux/ptp_clock_kernel.h>
+#include <linux/net_tstamp.h>
+#include <linux/clocksource.h>
+
 /* compilation time flags */
 
 /* define this to make the driver freeze on error to allow getting debug info
  * (you will need to reboot afterwards) */
 /* #define BNX2X_STOP_ON_ERROR */
 
-#define DRV_MODULE_VERSION      "1.78.19-0"
+#define DRV_MODULE_VERSION      "1.710.51-0"
 #define DRV_MODULE_RELDATE      "2014/02/10"
 #define BNX2X_BC_VER            0x040200
 
@@ -70,6 +74,7 @@ enum bnx2x_int_mode {
 #define BNX2X_MSG_SP                   0x0100000 /* was: NETIF_MSG_INTR */
 #define BNX2X_MSG_FP                   0x0200000 /* was: NETIF_MSG_INTR */
 #define BNX2X_MSG_IOV                  0x0800000
+#define BNX2X_MSG_PTP                  0x1000000
 #define BNX2X_MSG_IDLE                 0x2000000 /* used for idle check*/
 #define BNX2X_MSG_ETHTOOL              0x4000000
 #define BNX2X_MSG_DCB                  0x8000000
@@ -1587,10 +1592,11 @@ struct bnx2x {
 #define USING_SINGLE_MSIX_FLAG         (1 << 20)
 #define BC_SUPPORTS_DCBX_MSG_NON_PMF   (1 << 21)
 #define IS_VF_FLAG                     (1 << 22)
-#define INTERRUPTS_ENABLED_FLAG                (1 << 23)
-#define BC_SUPPORTS_RMMOD_CMD          (1 << 24)
-#define HAS_PHYS_PORT_ID               (1 << 25)
-#define AER_ENABLED                    (1 << 26)
+#define BC_SUPPORTS_RMMOD_CMD          (1 << 23)
+#define HAS_PHYS_PORT_ID               (1 << 24)
+#define AER_ENABLED                    (1 << 25)
+#define PTP_SUPPORTED                  (1 << 26)
+#define TX_TIMESTAMPING_EN             (1 << 27)
 
 #define BP_NOMCP(bp)                   ((bp)->flags & NO_MCP_FLAG)
 
@@ -1684,13 +1690,9 @@ struct bnx2x {
 #define BNX2X_STATE_ERROR              0xf000
 
 #define BNX2X_MAX_PRIORITY             8
-#define BNX2X_MAX_ENTRIES_PER_PRI      16
-#define BNX2X_MAX_COS                  3
-#define BNX2X_MAX_TX_COS               2
        int                     num_queues;
        uint                    num_ethernet_queues;
        uint                    num_cnic_queues;
-       int                     num_napi_queues;
        int                     disable_tpa;
 
        u32                     rx_mode;
@@ -1933,6 +1935,19 @@ struct bnx2x {
 
        u8                                      phys_port_id[ETH_ALEN];
 
+       /* PTP related context */
+       struct ptp_clock *ptp_clock;
+       struct ptp_clock_info ptp_clock_info;
+       struct work_struct ptp_task;
+       struct cyclecounter cyclecounter;
+       struct timecounter timecounter;
+       bool timecounter_init_done;
+       struct sk_buff *ptp_tx_skb;
+       unsigned long ptp_tx_start;
+       bool hwtstamp_ioctl_called;
+       u16 tx_type;
+       u16 rx_filter;
+
        struct bnx2x_link_report_data           vf_link_vars;
 };
 
@@ -2559,4 +2574,11 @@ void bnx2x_update_mng_version(struct bnx2x *bp);
 
 #define E1H_MAX_MF_SB_COUNT (HC_SB_MAX_SB_E1X/(E1HVN_MAX * PORT_MAX))
 
+void bnx2x_init_ptp(struct bnx2x *bp);
+int bnx2x_configure_ptp_filters(struct bnx2x *bp);
+void bnx2x_set_rx_ts(struct bnx2x *bp, struct sk_buff *skb);
+
+#define BNX2X_MAX_PHC_DRIFT 31000000
+#define BNX2X_PTP_TX_TIMEOUT
+
 #endif /* bnx2x.h */
index 4e6c82e2022492ef02b142ac13950fbf4e3a7fef..6dc32aee96bfd40634742da87233bdf60f862476 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/if_vlan.h>
 #include <linux/interrupt.h>
 #include <linux/ip.h>
+#include <linux/crash_dump.h>
 #include <net/tcp.h>
 #include <net/ipv6.h>
 #include <net/ip6_checksum.h>
@@ -64,7 +65,7 @@ static int bnx2x_calc_num_queues(struct bnx2x *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)
+       if (is_kdump_kernel())
                nq = 1;
 
        nq = clamp(nq, 1, BNX2X_MAX_QUEUES(bp));
@@ -483,11 +484,7 @@ static void bnx2x_tpa_start(struct bnx2x_fastpath *fp, u16 queue,
 
 #ifdef BNX2X_STOP_ON_ERROR
        fp->tpa_queue_used |= (1 << queue);
-#ifdef _ASM_GENERIC_INT_L64_H
-       DP(NETIF_MSG_RX_STATUS, "fp->tpa_queue_used = 0x%lx\n",
-#else
        DP(NETIF_MSG_RX_STATUS, "fp->tpa_queue_used = 0x%llx\n",
-#endif
           fp->tpa_queue_used);
 #endif
 }
@@ -1067,6 +1064,11 @@ reuse_rx:
 
                skb_record_rx_queue(skb, fp->rx_queue);
 
+               /* Check if this packet was timestamped */
+               if (unlikely(cqe->fast_path_cqe.type_error_flags &
+                            (1 << ETH_FAST_PATH_RX_CQE_PTP_PKT_SHIFT)))
+                       bnx2x_set_rx_ts(bp, skb);
+
                if (le16_to_cpu(cqe_fp->pars_flags.flags) &
                    PARSING_FLAGS_VLAN)
                        __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
@@ -2082,6 +2084,10 @@ int bnx2x_rss(struct bnx2x *bp, struct bnx2x_rss_config_obj *rss_obj,
                        __set_bit(BNX2X_RSS_IPV4_UDP, &params.rss_flags);
                if (rss_obj->udp_rss_v6)
                        __set_bit(BNX2X_RSS_IPV6_UDP, &params.rss_flags);
+
+               if (!CHIP_IS_E1x(bp))
+                       /* valid only for TUNN_MODE_GRE tunnel mode */
+                       __set_bit(BNX2X_RSS_GRE_INNER_HDRS, &params.rss_flags);
        } else {
                __set_bit(BNX2X_RSS_MODE_DISABLED, &params.rss_flags);
        }
@@ -2804,7 +2810,11 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
        /* Initialize Rx filter. */
        bnx2x_set_rx_mode_inner(bp);
 
-       /* Start the Tx */
+       if (bp->flags & PTP_SUPPORTED) {
+               bnx2x_init_ptp(bp);
+               bnx2x_configure_ptp_filters(bp);
+       }
+       /* Start Tx */
        switch (load_mode) {
        case LOAD_NORMAL:
                /* Tx queue should be only re-enabled */
@@ -3441,26 +3451,6 @@ exit_lbl:
 }
 #endif
 
-static void bnx2x_set_pbd_gso_e2(struct sk_buff *skb, u32 *parsing_data,
-                                u32 xmit_type)
-{
-       struct ipv6hdr *ipv6;
-
-       *parsing_data |= (skb_shinfo(skb)->gso_size <<
-                             ETH_TX_PARSE_BD_E2_LSO_MSS_SHIFT) &
-                             ETH_TX_PARSE_BD_E2_LSO_MSS;
-
-       if (xmit_type & XMIT_GSO_ENC_V6)
-               ipv6 = inner_ipv6_hdr(skb);
-       else if (xmit_type & XMIT_GSO_V6)
-               ipv6 = ipv6_hdr(skb);
-       else
-               ipv6 = NULL;
-
-       if (ipv6 && ipv6->nexthdr == NEXTHDR_IPV6)
-               *parsing_data |= ETH_TX_PARSE_BD_E2_IPV6_WITH_EXT_HDR;
-}
-
 /**
  * bnx2x_set_pbd_gso - update PBD in GSO case.
  *
@@ -3470,7 +3460,6 @@ static void bnx2x_set_pbd_gso_e2(struct sk_buff *skb, u32 *parsing_data,
  */
 static void bnx2x_set_pbd_gso(struct sk_buff *skb,
                              struct eth_tx_parse_bd_e1x *pbd,
-                             struct eth_tx_start_bd *tx_start_bd,
                              u32 xmit_type)
 {
        pbd->lso_mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
@@ -3483,9 +3472,6 @@ static void bnx2x_set_pbd_gso(struct sk_buff *skb,
                        bswab16(~csum_tcpudp_magic(ip_hdr(skb)->saddr,
                                                   ip_hdr(skb)->daddr,
                                                   0, IPPROTO_TCP, 0));
-
-               /* GSO on 57710/57711 needs FW to calculate IP checksum */
-               tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_IP_CSUM;
        } else {
                pbd->tcp_pseudo_csum =
                        bswab16(~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
@@ -3657,18 +3643,23 @@ static void bnx2x_update_pbds_gso_enc(struct sk_buff *skb,
                           (__force u32)iph->tot_len -
                           (__force u32)iph->frag_off;
 
+               outerip_len = iph->ihl << 1;
+
                pbd2->fw_ip_csum_wo_len_flags_frag =
                        bswab16(csum_fold((__force __wsum)csum));
        } else {
                pbd2->fw_ip_hdr_to_payload_w =
                        hlen_w - ((sizeof(struct ipv6hdr)) >> 1);
+               pbd_e2->data.tunnel_data.flags |=
+                       ETH_TUNNEL_DATA_IP_HDR_TYPE_OUTER;
        }
 
        pbd2->tcp_send_seq = bswab32(inner_tcp_hdr(skb)->seq);
 
        pbd2->tcp_flags = pbd_tcp_flags(inner_tcp_hdr(skb));
 
-       if (xmit_type & XMIT_GSO_V4) {
+       /* inner IP header info */
+       if (xmit_type & XMIT_CSUM_ENC_V4) {
                pbd2->hw_ip_id = bswab16(inner_ip_hdr(skb)->id);
 
                pbd_e2->data.tunnel_data.pseudo_csum =
@@ -3676,8 +3667,6 @@ static void bnx2x_update_pbds_gso_enc(struct sk_buff *skb,
                                        inner_ip_hdr(skb)->saddr,
                                        inner_ip_hdr(skb)->daddr,
                                        0, IPPROTO_TCP, 0));
-
-               outerip_len = ip_hdr(skb)->ihl << 1;
        } else {
                pbd_e2->data.tunnel_data.pseudo_csum =
                        bswab16(~csum_ipv6_magic(
@@ -3690,8 +3679,6 @@ static void bnx2x_update_pbds_gso_enc(struct sk_buff *skb,
 
        *global_data |=
                outerip_off |
-               (!!(xmit_type & XMIT_CSUM_V6) <<
-                       ETH_TX_PARSE_2ND_BD_IP_HDR_TYPE_OUTER_SHIFT) |
                (outerip_len <<
                        ETH_TX_PARSE_2ND_BD_IP_HDR_LEN_OUTER_W_SHIFT) |
                ((skb->protocol == cpu_to_be16(ETH_P_8021Q)) <<
@@ -3703,6 +3690,23 @@ static void bnx2x_update_pbds_gso_enc(struct sk_buff *skb,
        }
 }
 
+static inline void bnx2x_set_ipv6_ext_e2(struct sk_buff *skb, u32 *parsing_data,
+                                        u32 xmit_type)
+{
+       struct ipv6hdr *ipv6;
+
+       if (!(xmit_type & (XMIT_GSO_ENC_V6 | XMIT_GSO_V6)))
+               return;
+
+       if (xmit_type & XMIT_GSO_ENC_V6)
+               ipv6 = inner_ipv6_hdr(skb);
+       else /* XMIT_GSO_V6 */
+               ipv6 = ipv6_hdr(skb);
+
+       if (ipv6->nexthdr == NEXTHDR_IPV6)
+               *parsing_data |= ETH_TX_PARSE_BD_E2_IPV6_WITH_EXT_HDR;
+}
+
 /* called with netif_tx_lock
  * bnx2x_tx_int() runs without netif_tx_lock unless it needs to call
  * netif_wake_queue()
@@ -3835,6 +3839,20 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        tx_start_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_START_BD;
 
+       if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
+               if (!(bp->flags & TX_TIMESTAMPING_EN)) {
+                       BNX2X_ERR("Tx timestamping was not enabled, this packet will not be timestamped\n");
+               } else if (bp->ptp_tx_skb) {
+                       BNX2X_ERR("The device supports only a single outstanding packet to timestamp, this packet will not be timestamped\n");
+               } else {
+                       skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+                       /* schedule check for Tx timestamp */
+                       bp->ptp_tx_skb = skb_get(skb);
+                       bp->ptp_tx_start = jiffies;
+                       schedule_work(&bp->ptp_task);
+               }
+       }
+
        /* header nbd: indirectly zero other flags! */
        tx_start_bd->general_data = 1 << ETH_TX_START_BD_HDR_NBDS_SHIFT;
 
@@ -3856,12 +3874,16 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
                /* when transmitting in a vf, start bd must hold the ethertype
                 * for fw to enforce it
                 */
+#ifndef BNX2X_STOP_ON_ERROR
                if (IS_VF(bp))
+#endif
                        tx_start_bd->vlan_or_ethertype =
                                cpu_to_le16(ntohs(eth->h_proto));
+#ifndef BNX2X_STOP_ON_ERROR
                else
                        /* used by FW for packet accounting */
                        tx_start_bd->vlan_or_ethertype = cpu_to_le16(pkt_prod);
+#endif
        }
 
        nbd = 2; /* start_bd + pbd + frags (updated when pages are mapped) */
@@ -3919,6 +3941,7 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
                                                     xmit_type);
                }
 
+               bnx2x_set_ipv6_ext_e2(skb, &pbd_e2_parsing_data, xmit_type);
                /* Add the macs to the parsing BD if this is a vf or if
                 * Tx Switching is enabled.
                 */
@@ -3933,11 +3956,22 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
                                              &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,
-                                             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,
+                                               eth->h_dest);
+#ifdef BNX2X_STOP_ON_ERROR
+                       /* Enforce security is always set in Stop on Error -
+                        * source mac should be present in the parsing BD
+                        */
+                       bnx2x_set_fw_mac_addr(&pbd_e2->data.mac_addr.src_hi,
+                                             &pbd_e2->data.mac_addr.src_mid,
+                                             &pbd_e2->data.mac_addr.src_lo,
+                                             eth->h_source);
+#endif
                }
 
                SET_FLAG(pbd_e2_parsing_data,
@@ -3984,10 +4018,12 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
                                                 bd_prod);
                }
                if (!CHIP_IS_E1x(bp))
-                       bnx2x_set_pbd_gso_e2(skb, &pbd_e2_parsing_data,
-                                            xmit_type);
+                       pbd_e2_parsing_data |=
+                               (skb_shinfo(skb)->gso_size <<
+                                ETH_TX_PARSE_BD_E2_LSO_MSS_SHIFT) &
+                                ETH_TX_PARSE_BD_E2_LSO_MSS;
                else
-                       bnx2x_set_pbd_gso(skb, pbd_e1x, first_bd, xmit_type);
+                       bnx2x_set_pbd_gso(skb, pbd_e1x, xmit_type);
        }
 
        /* Set the PBD's parsing_data field if not zero
@@ -4775,11 +4811,15 @@ netdev_features_t bnx2x_fix_features(struct net_device *dev,
        struct bnx2x *bp = netdev_priv(dev);
 
        /* TPA requires Rx CSUM offloading */
-       if (!(features & NETIF_F_RXCSUM) || bp->disable_tpa) {
+       if (!(features & NETIF_F_RXCSUM)) {
                features &= ~NETIF_F_LRO;
                features &= ~NETIF_F_GRO;
        }
 
+       /* Note: do not disable SW GRO in kernel when HW GRO is off */
+       if (bp->disable_tpa)
+               features &= ~NETIF_F_LRO;
+
        return features;
 }
 
@@ -4818,6 +4858,10 @@ int bnx2x_set_features(struct net_device *dev, netdev_features_t features)
        if ((changes & GRO_ENABLE_FLAG) && (flags & TPA_ENABLE_FLAG))
                changes &= ~GRO_ENABLE_FLAG;
 
+       /* if GRO is changed while HW TPA is off, don't force a reload */
+       if ((changes & GRO_ENABLE_FLAG) && bp->disable_tpa)
+               changes &= ~GRO_ENABLE_FLAG;
+
        if (changes)
                bnx2x_reload = true;
 
index 571427c7226b11f4c22669ce8d8f14c81950a10d..ac63e16829efc3552ed2cc0ca7df5685e339476c 100644 (file)
@@ -932,8 +932,9 @@ 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 = L2GRE_TUNNEL;
-       start_params->gre_tunnel_rss = GRE_INNER_HEADERS_RSS;
+       start_params->tunnel_mode       = TUNN_MODE_GRE;
+       start_params->gre_tunnel_type   = IPGRE_TUNNEL;
+       start_params->inner_gre_rss_en  = 1;
 
        return bnx2x_func_state_change(bp, &func_params);
 }
index fb26bc4c42a1fd03d42ef885dc562bcf4d460ade..6e4294ed1fc997e5545fcc48a24c92124129867c 100644 (file)
@@ -2092,7 +2092,6 @@ static void bnx2x_dcbnl_get_pfc_cfg(struct net_device *netdev, int prio,
 static u8 bnx2x_dcbnl_set_all(struct net_device *netdev)
 {
        struct bnx2x *bp = netdev_priv(netdev);
-       int rc = 0;
 
        DP(BNX2X_MSG_DCB, "SET-ALL\n");
 
@@ -2110,9 +2109,7 @@ static u8 bnx2x_dcbnl_set_all(struct net_device *netdev)
                                       1);
                bnx2x_dcbx_init(bp, true);
        }
-       DP(BNX2X_MSG_DCB, "set_dcbx_params done (%d)\n", rc);
-       if (rc)
-               return 1;
+       DP(BNX2X_MSG_DCB, "set_dcbx_params done\n");
 
        return 0;
 }
index 12eb4baee9f642e444bbb162d038911776b4d852..741aa130c19f4efb4df2e2b64b166f24bd4b6b3e 100644 (file)
@@ -40,7 +40,7 @@ struct        dump_header {
        u32 dump_meta_data; /* OR of CHIP and PATH. */
 };
 
-#define BNX2X_DUMP_VERSION 0x50acff01
+#define  BNX2X_DUMP_VERSION 0x61111111
 struct reg_addr {
        u32 addr;
        u32 size;
@@ -1464,7 +1464,6 @@ static const struct reg_addr reg_addrs[] = {
        { 0x180398, 1, 0x1c, 0x924},
        { 0x1803a0, 5, 0x1c, 0x924},
        { 0x1803b4, 2, 0x18, 0x924},
-       { 0x180400, 256, 0x3, 0xfff},
        { 0x181000, 4, 0x1f, 0x93c},
        { 0x181010, 1020, 0x1f, 0x38},
        { 0x182000, 4, 0x18, 0x924},
@@ -1576,7 +1575,6 @@ static const struct reg_addr reg_addrs[] = {
        { 0x200398, 1, 0x1c, 0x924},
        { 0x2003a0, 1, 0x1c, 0x924},
        { 0x2003a8, 2, 0x1c, 0x924},
-       { 0x200400, 256, 0x3, 0xfff},
        { 0x202000, 4, 0x1f, 0x1927},
        { 0x202010, 2044, 0x1f, 0x1007},
        { 0x204000, 4, 0x18, 0x924},
@@ -1688,7 +1686,6 @@ static const struct reg_addr reg_addrs[] = {
        { 0x280398, 1, 0x1c, 0x924},
        { 0x2803a0, 1, 0x1c, 0x924},
        { 0x2803a8, 2, 0x1c, 0x924},
-       { 0x280400, 256, 0x3, 0xfff},
        { 0x282000, 4, 0x1f, 0x9e4},
        { 0x282010, 2044, 0x1f, 0x1c0},
        { 0x284000, 4, 0x18, 0x924},
@@ -1800,7 +1797,6 @@ static const struct reg_addr reg_addrs[] = {
        { 0x300398, 1, 0x1c, 0x924},
        { 0x3003a0, 1, 0x1c, 0x924},
        { 0x3003a8, 2, 0x1c, 0x924},
-       { 0x300400, 256, 0x3, 0xfff},
        { 0x302000, 4, 0x1f, 0xf24},
        { 0x302010, 2044, 0x1f, 0xe00},
        { 0x304000, 4, 0x18, 0x924},
@@ -2206,10 +2202,10 @@ static const struct wreg_addr wreg_addr_e3b0 = {
        0x1b0c00, 128, 2, read_reg_e3b0, 0x1f, 0x1fff};
 
 static const unsigned int dump_num_registers[NUM_CHIPS][NUM_PRESETS] = {
-       {20782, 18567, 27975, 19729, 18311, 27719, 20836, 32391, 41799, 20812,
-        26247, 35655, 19074},
-       {32774, 19297, 33277, 31721, 19041, 33021, 32828, 33121, 47101, 32804,
-        26977, 40957, 35895},
+       {19758, 17543, 26951, 18705, 17287, 26695, 19812, 31367, 40775, 19788,
+        25223, 34631, 19074},
+       {31750, 18273, 32253, 30697, 18017, 31997, 31804, 32097, 46077, 31780,
+        25953, 39933, 35895},
        {36527, 17928, 33697, 35474, 18700, 34466, 36581, 31752, 47521, 36557,
         25608, 41377, 43903},
        {45239, 17936, 34387, 44186, 18708, 35156, 45293, 31760, 48211, 45269,
index 92fee842f954f8787b245c007deb5291ca8c8771..0b173ed20ae9db65fa8a3d65d4ea80be58d076bd 100644 (file)
@@ -3481,6 +3481,46 @@ static int bnx2x_set_channels(struct net_device *dev,
        return bnx2x_nic_load(bp, LOAD_NORMAL);
 }
 
+static int bnx2x_get_ts_info(struct net_device *dev,
+                            struct ethtool_ts_info *info)
+{
+       struct bnx2x *bp = netdev_priv(dev);
+
+       if (bp->flags & PTP_SUPPORTED) {
+               info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
+                                       SOF_TIMESTAMPING_RX_SOFTWARE |
+                                       SOF_TIMESTAMPING_SOFTWARE |
+                                       SOF_TIMESTAMPING_TX_HARDWARE |
+                                       SOF_TIMESTAMPING_RX_HARDWARE |
+                                       SOF_TIMESTAMPING_RAW_HARDWARE;
+
+               if (bp->ptp_clock)
+                       info->phc_index = ptp_clock_index(bp->ptp_clock);
+               else
+                       info->phc_index = -1;
+
+               info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
+                                  (1 << HWTSTAMP_FILTER_PTP_V1_L4_EVENT) |
+                                  (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) |
+                                  (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) |
+                                  (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) |
+                                  (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) |
+                                  (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) |
+                                  (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) |
+                                  (1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) |
+                                  (1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) |
+                                  (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) |
+                                  (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) |
+                                  (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ);
+
+               info->tx_types = (1 << HWTSTAMP_TX_OFF)|(1 << HWTSTAMP_TX_ON);
+
+               return 0;
+       }
+
+       return ethtool_op_get_ts_info(dev, info);
+}
+
 static const struct ethtool_ops bnx2x_ethtool_ops = {
        .get_settings           = bnx2x_get_settings,
        .set_settings           = bnx2x_set_settings,
@@ -3522,7 +3562,7 @@ static const struct ethtool_ops bnx2x_ethtool_ops = {
        .get_module_eeprom      = bnx2x_get_module_eeprom,
        .get_eee                = bnx2x_get_eee,
        .set_eee                = bnx2x_set_eee,
-       .get_ts_info            = ethtool_op_get_ts_info,
+       .get_ts_info            = bnx2x_get_ts_info,
 };
 
 static const struct ethtool_ops bnx2x_vf_ethtool_ops = {
index 95dc365435483ed9298389b88f965130d48eb7d0..7636e3c18771dced3a1d4bd3db0018cee4b4d7f3 100644 (file)
 #ifndef BNX2X_FW_DEFS_H
 #define BNX2X_FW_DEFS_H
 
-#define CSTORM_ASSERT_LIST_INDEX_OFFSET        (IRO[148].base)
+#define CSTORM_ASSERT_LIST_INDEX_OFFSET        (IRO[152].base)
 #define CSTORM_ASSERT_LIST_OFFSET(assertListEntry) \
-       (IRO[147].base + ((assertListEntry) * IRO[147].m1))
+       (IRO[151].base + ((assertListEntry) * IRO[151].m1))
 #define CSTORM_EVENT_RING_DATA_OFFSET(pfId) \
-       (IRO[153].base + (((pfId)>>1) * IRO[153].m1) + (((pfId)&1) * \
-       IRO[153].m2))
+       (IRO[157].base + (((pfId)>>1) * IRO[157].m1) + (((pfId)&1) * \
+       IRO[157].m2))
 #define CSTORM_EVENT_RING_PROD_OFFSET(pfId) \
-       (IRO[154].base + (((pfId)>>1) * IRO[154].m1) + (((pfId)&1) * \
-       IRO[154].m2))
+       (IRO[158].base + (((pfId)>>1) * IRO[158].m1) + (((pfId)&1) * \
+       IRO[158].m2))
 #define CSTORM_FINAL_CLEANUP_COMPLETE_OFFSET(funcId) \
-       (IRO[159].base + ((funcId) * IRO[159].m1))
+       (IRO[163].base + ((funcId) * IRO[163].m1))
 #define CSTORM_FUNC_EN_OFFSET(funcId) \
-       (IRO[149].base + ((funcId) * IRO[149].m1))
+       (IRO[153].base + ((funcId) * IRO[153].m1))
 #define CSTORM_HC_SYNC_LINE_INDEX_E1X_OFFSET(hcIndex, sbId) \
-       (IRO[139].base + ((hcIndex) * IRO[139].m1) + ((sbId) * IRO[139].m2))
+       (IRO[143].base + ((hcIndex) * IRO[143].m1) + ((sbId) * IRO[143].m2))
 #define CSTORM_HC_SYNC_LINE_INDEX_E2_OFFSET(hcIndex, sbId) \
-       (IRO[138].base + (((hcIndex)>>2) * IRO[138].m1) + (((hcIndex)&3) \
-       * IRO[138].m2) + ((sbId) * IRO[138].m3))
-#define CSTORM_IGU_MODE_OFFSET (IRO[157].base)
+       (IRO[142].base + (((hcIndex)>>2) * IRO[142].m1) + (((hcIndex)&3) \
+       * IRO[142].m2) + ((sbId) * IRO[142].m3))
+#define CSTORM_IGU_MODE_OFFSET (IRO[161].base)
 #define CSTORM_ISCSI_CQ_SIZE_OFFSET(pfId) \
-       (IRO[317].base + ((pfId) * IRO[317].m1))
+       (IRO[323].base + ((pfId) * IRO[323].m1))
 #define CSTORM_ISCSI_CQ_SQN_SIZE_OFFSET(pfId) \
-       (IRO[318].base + ((pfId) * IRO[318].m1))
+       (IRO[324].base + ((pfId) * IRO[324].m1))
 #define CSTORM_ISCSI_EQ_CONS_OFFSET(pfId, iscsiEqId) \
-       (IRO[310].base + ((pfId) * IRO[310].m1) + ((iscsiEqId) * IRO[310].m2))
+       (IRO[316].base + ((pfId) * IRO[316].m1) + ((iscsiEqId) * IRO[316].m2))
 #define CSTORM_ISCSI_EQ_NEXT_EQE_ADDR_OFFSET(pfId, iscsiEqId) \
-       (IRO[312].base + ((pfId) * IRO[312].m1) + ((iscsiEqId) * IRO[312].m2))
+       (IRO[318].base + ((pfId) * IRO[318].m1) + ((iscsiEqId) * IRO[318].m2))
 #define CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_OFFSET(pfId, iscsiEqId) \
-       (IRO[311].base + ((pfId) * IRO[311].m1) + ((iscsiEqId) * IRO[311].m2))
+       (IRO[317].base + ((pfId) * IRO[317].m1) + ((iscsiEqId) * IRO[317].m2))
 #define CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_VALID_OFFSET(pfId, iscsiEqId) \
-       (IRO[313].base + ((pfId) * IRO[313].m1) + ((iscsiEqId) * IRO[313].m2))
+       (IRO[319].base + ((pfId) * IRO[319].m1) + ((iscsiEqId) * IRO[319].m2))
 #define CSTORM_ISCSI_EQ_PROD_OFFSET(pfId, iscsiEqId) \
-       (IRO[309].base + ((pfId) * IRO[309].m1) + ((iscsiEqId) * IRO[309].m2))
-#define CSTORM_ISCSI_EQ_SB_INDEX_OFFSET(pfId, iscsiEqId) \
        (IRO[315].base + ((pfId) * IRO[315].m1) + ((iscsiEqId) * IRO[315].m2))
+#define CSTORM_ISCSI_EQ_SB_INDEX_OFFSET(pfId, iscsiEqId) \
+       (IRO[321].base + ((pfId) * IRO[321].m1) + ((iscsiEqId) * IRO[321].m2))
 #define CSTORM_ISCSI_EQ_SB_NUM_OFFSET(pfId, iscsiEqId) \
-       (IRO[314].base + ((pfId) * IRO[314].m1) + ((iscsiEqId) * IRO[314].m2))
+       (IRO[320].base + ((pfId) * IRO[320].m1) + ((iscsiEqId) * IRO[320].m2))
 #define CSTORM_ISCSI_HQ_SIZE_OFFSET(pfId) \
-       (IRO[316].base + ((pfId) * IRO[316].m1))
+       (IRO[322].base + ((pfId) * IRO[322].m1))
 #define CSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfId) \
-       (IRO[308].base + ((pfId) * IRO[308].m1))
+       (IRO[314].base + ((pfId) * IRO[314].m1))
 #define CSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfId) \
-       (IRO[307].base + ((pfId) * IRO[307].m1))
+       (IRO[313].base + ((pfId) * IRO[313].m1))
 #define CSTORM_ISCSI_PAGE_SIZE_OFFSET(pfId) \
-       (IRO[306].base + ((pfId) * IRO[306].m1))
+       (IRO[312].base + ((pfId) * IRO[312].m1))
 #define CSTORM_RECORD_SLOW_PATH_OFFSET(funcId) \
-       (IRO[151].base + ((funcId) * IRO[151].m1))
+       (IRO[155].base + ((funcId) * IRO[155].m1))
 #define CSTORM_SP_STATUS_BLOCK_DATA_OFFSET(pfId) \
-       (IRO[142].base + ((pfId) * IRO[142].m1))
+       (IRO[146].base + ((pfId) * IRO[146].m1))
 #define CSTORM_SP_STATUS_BLOCK_DATA_STATE_OFFSET(pfId) \
-       (IRO[143].base + ((pfId) * IRO[143].m1))
+       (IRO[147].base + ((pfId) * IRO[147].m1))
 #define CSTORM_SP_STATUS_BLOCK_OFFSET(pfId) \
-       (IRO[141].base + ((pfId) * IRO[141].m1))
-#define CSTORM_SP_STATUS_BLOCK_SIZE (IRO[141].size)
+       (IRO[145].base + ((pfId) * IRO[145].m1))
+#define CSTORM_SP_STATUS_BLOCK_SIZE (IRO[145].size)
 #define CSTORM_SP_SYNC_BLOCK_OFFSET(pfId) \
-       (IRO[144].base + ((pfId) * IRO[144].m1))
-#define CSTORM_SP_SYNC_BLOCK_SIZE (IRO[144].size)
+       (IRO[148].base + ((pfId) * IRO[148].m1))
+#define CSTORM_SP_SYNC_BLOCK_SIZE (IRO[148].size)
 #define CSTORM_STATUS_BLOCK_DATA_FLAGS_OFFSET(sbId, hcIndex) \
-       (IRO[136].base + ((sbId) * IRO[136].m1) + ((hcIndex) * IRO[136].m2))
+       (IRO[140].base + ((sbId) * IRO[140].m1) + ((hcIndex) * IRO[140].m2))
 #define CSTORM_STATUS_BLOCK_DATA_OFFSET(sbId) \
-       (IRO[133].base + ((sbId) * IRO[133].m1))
+       (IRO[137].base + ((sbId) * IRO[137].m1))
 #define CSTORM_STATUS_BLOCK_DATA_STATE_OFFSET(sbId) \
-       (IRO[134].base + ((sbId) * IRO[134].m1))
+       (IRO[138].base + ((sbId) * IRO[138].m1))
 #define CSTORM_STATUS_BLOCK_DATA_TIMEOUT_OFFSET(sbId, hcIndex) \
-       (IRO[135].base + ((sbId) * IRO[135].m1) + ((hcIndex) * IRO[135].m2))
+       (IRO[139].base + ((sbId) * IRO[139].m1) + ((hcIndex) * IRO[139].m2))
 #define CSTORM_STATUS_BLOCK_OFFSET(sbId) \
-       (IRO[132].base + ((sbId) * IRO[132].m1))
-#define CSTORM_STATUS_BLOCK_SIZE (IRO[132].size)
+       (IRO[136].base + ((sbId) * IRO[136].m1))
+#define CSTORM_STATUS_BLOCK_SIZE (IRO[136].size)
 #define CSTORM_SYNC_BLOCK_OFFSET(sbId) \
-       (IRO[137].base + ((sbId) * IRO[137].m1))
-#define CSTORM_SYNC_BLOCK_SIZE (IRO[137].size)
+       (IRO[141].base + ((sbId) * IRO[141].m1))
+#define CSTORM_SYNC_BLOCK_SIZE (IRO[141].size)
 #define CSTORM_VF_PF_CHANNEL_STATE_OFFSET(vfId) \
-       (IRO[155].base + ((vfId) * IRO[155].m1))
+       (IRO[159].base + ((vfId) * IRO[159].m1))
 #define CSTORM_VF_PF_CHANNEL_VALID_OFFSET(vfId) \
-       (IRO[156].base + ((vfId) * IRO[156].m1))
+       (IRO[160].base + ((vfId) * IRO[160].m1))
 #define CSTORM_VF_TO_PF_OFFSET(funcId) \
-       (IRO[150].base + ((funcId) * IRO[150].m1))
+       (IRO[154].base + ((funcId) * IRO[154].m1))
 #define TSTORM_APPROXIMATE_MATCH_MULTICAST_FILTERING_OFFSET(pfId) \
-       (IRO[203].base + ((pfId) * IRO[203].m1))
+       (IRO[207].base + ((pfId) * IRO[207].m1))
 #define TSTORM_ASSERT_LIST_INDEX_OFFSET        (IRO[102].base)
 #define TSTORM_ASSERT_LIST_OFFSET(assertListEntry) \
        (IRO[101].base + ((assertListEntry) * IRO[101].m1))
 #define TSTORM_FUNCTION_COMMON_CONFIG_OFFSET(pfId) \
-       (IRO[201].base + ((pfId) * IRO[201].m1))
+       (IRO[205].base + ((pfId) * IRO[205].m1))
 #define TSTORM_FUNC_EN_OFFSET(funcId) \
-       (IRO[103].base + ((funcId) * IRO[103].m1))
+       (IRO[107].base + ((funcId) * IRO[107].m1))
 #define TSTORM_ISCSI_ERROR_BITMAP_OFFSET(pfId) \
-       (IRO[272].base + ((pfId) * IRO[272].m1))
+       (IRO[278].base + ((pfId) * IRO[278].m1))
 #define TSTORM_ISCSI_L2_ISCSI_OOO_CID_TABLE_OFFSET(pfId) \
-       (IRO[273].base + ((pfId) * IRO[273].m1))
+       (IRO[279].base + ((pfId) * IRO[279].m1))
 #define TSTORM_ISCSI_L2_ISCSI_OOO_CLIENT_ID_TABLE_OFFSET(pfId) \
-       (IRO[274].base + ((pfId) * IRO[274].m1))
+       (IRO[280].base + ((pfId) * IRO[280].m1))
 #define TSTORM_ISCSI_L2_ISCSI_OOO_PROD_OFFSET(pfId) \
-       (IRO[275].base + ((pfId) * IRO[275].m1))
+       (IRO[281].base + ((pfId) * IRO[281].m1))
 #define TSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfId) \
-       (IRO[271].base + ((pfId) * IRO[271].m1))
+       (IRO[277].base + ((pfId) * IRO[277].m1))
 #define TSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfId) \
-       (IRO[270].base + ((pfId) * IRO[270].m1))
+       (IRO[276].base + ((pfId) * IRO[276].m1))
 #define TSTORM_ISCSI_PAGE_SIZE_OFFSET(pfId) \
-       (IRO[269].base + ((pfId) * IRO[269].m1))
+       (IRO[275].base + ((pfId) * IRO[275].m1))
 #define TSTORM_ISCSI_RQ_SIZE_OFFSET(pfId) \
-       (IRO[268].base + ((pfId) * IRO[268].m1))
+       (IRO[274].base + ((pfId) * IRO[274].m1))
 #define TSTORM_ISCSI_TCP_LOCAL_ADV_WND_OFFSET(pfId) \
-       (IRO[278].base + ((pfId) * IRO[278].m1))
+       (IRO[284].base + ((pfId) * IRO[284].m1))
 #define TSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(pfId) \
-       (IRO[264].base + ((pfId) * IRO[264].m1))
+       (IRO[270].base + ((pfId) * IRO[270].m1))
 #define TSTORM_ISCSI_TCP_VARS_LSB_LOCAL_MAC_ADDR_OFFSET(pfId) \
-       (IRO[265].base + ((pfId) * IRO[265].m1))
+       (IRO[271].base + ((pfId) * IRO[271].m1))
 #define TSTORM_ISCSI_TCP_VARS_MID_LOCAL_MAC_ADDR_OFFSET(pfId) \
-       (IRO[266].base + ((pfId) * IRO[266].m1))
+       (IRO[272].base + ((pfId) * IRO[272].m1))
 #define TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(pfId) \
-       (IRO[267].base + ((pfId) * IRO[267].m1))
+       (IRO[273].base + ((pfId) * IRO[273].m1))
 #define TSTORM_MAC_FILTER_CONFIG_OFFSET(pfId) \
-       (IRO[202].base + ((pfId) * IRO[202].m1))
+       (IRO[206].base + ((pfId) * IRO[206].m1))
 #define TSTORM_RECORD_SLOW_PATH_OFFSET(funcId) \
-       (IRO[105].base + ((funcId) * IRO[105].m1))
+       (IRO[109].base + ((funcId) * IRO[109].m1))
 #define TSTORM_TCP_MAX_CWND_OFFSET(pfId) \
-       (IRO[217].base + ((pfId) * IRO[217].m1))
+       (IRO[223].base + ((pfId) * IRO[223].m1))
 #define TSTORM_VF_TO_PF_OFFSET(funcId) \
-       (IRO[104].base + ((funcId) * IRO[104].m1))
-#define USTORM_AGG_DATA_OFFSET (IRO[206].base)
-#define USTORM_AGG_DATA_SIZE (IRO[206].size)
-#define USTORM_ASSERT_LIST_INDEX_OFFSET        (IRO[177].base)
+       (IRO[108].base + ((funcId) * IRO[108].m1))
+#define USTORM_AGG_DATA_OFFSET (IRO[212].base)
+#define USTORM_AGG_DATA_SIZE (IRO[212].size)
+#define USTORM_ASSERT_LIST_INDEX_OFFSET        (IRO[181].base)
 #define USTORM_ASSERT_LIST_OFFSET(assertListEntry) \
-       (IRO[176].base + ((assertListEntry) * IRO[176].m1))
+       (IRO[180].base + ((assertListEntry) * IRO[180].m1))
 #define USTORM_ETH_PAUSE_ENABLED_OFFSET(portId) \
-       (IRO[183].base + ((portId) * IRO[183].m1))
+       (IRO[187].base + ((portId) * IRO[187].m1))
 #define USTORM_FCOE_EQ_PROD_OFFSET(pfId) \
-       (IRO[319].base + ((pfId) * IRO[319].m1))
+       (IRO[325].base + ((pfId) * IRO[325].m1))
 #define USTORM_FUNC_EN_OFFSET(funcId) \
-       (IRO[178].base + ((funcId) * IRO[178].m1))
+       (IRO[182].base + ((funcId) * IRO[182].m1))
 #define USTORM_ISCSI_CQ_SIZE_OFFSET(pfId) \
-       (IRO[283].base + ((pfId) * IRO[283].m1))
+       (IRO[289].base + ((pfId) * IRO[289].m1))
 #define USTORM_ISCSI_CQ_SQN_SIZE_OFFSET(pfId) \
-       (IRO[284].base + ((pfId) * IRO[284].m1))
+       (IRO[290].base + ((pfId) * IRO[290].m1))
 #define USTORM_ISCSI_ERROR_BITMAP_OFFSET(pfId) \
-       (IRO[288].base + ((pfId) * IRO[288].m1))
+       (IRO[294].base + ((pfId) * IRO[294].m1))
 #define USTORM_ISCSI_GLOBAL_BUF_PHYS_ADDR_OFFSET(pfId) \
-       (IRO[285].base + ((pfId) * IRO[285].m1))
+       (IRO[291].base + ((pfId) * IRO[291].m1))
 #define USTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfId) \
-       (IRO[281].base + ((pfId) * IRO[281].m1))
+       (IRO[287].base + ((pfId) * IRO[287].m1))
 #define USTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfId) \
-       (IRO[280].base + ((pfId) * IRO[280].m1))
+       (IRO[286].base + ((pfId) * IRO[286].m1))
 #define USTORM_ISCSI_PAGE_SIZE_OFFSET(pfId) \
-       (IRO[279].base + ((pfId) * IRO[279].m1))
+       (IRO[285].base + ((pfId) * IRO[285].m1))
 #define USTORM_ISCSI_R2TQ_SIZE_OFFSET(pfId) \
-       (IRO[282].base + ((pfId) * IRO[282].m1))
+       (IRO[288].base + ((pfId) * IRO[288].m1))
 #define USTORM_ISCSI_RQ_BUFFER_SIZE_OFFSET(pfId) \
-       (IRO[286].base + ((pfId) * IRO[286].m1))
+       (IRO[292].base + ((pfId) * IRO[292].m1))
 #define USTORM_ISCSI_RQ_SIZE_OFFSET(pfId) \
-       (IRO[287].base + ((pfId) * IRO[287].m1))
+       (IRO[293].base + ((pfId) * IRO[293].m1))
 #define USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(pfId) \
-       (IRO[182].base + ((pfId) * IRO[182].m1))
+       (IRO[186].base + ((pfId) * IRO[186].m1))
 #define USTORM_RECORD_SLOW_PATH_OFFSET(funcId) \
-       (IRO[180].base + ((funcId) * IRO[180].m1))
+       (IRO[184].base + ((funcId) * IRO[184].m1))
 #define USTORM_RX_PRODS_E1X_OFFSET(portId, clientId) \
-       (IRO[209].base + ((portId) * IRO[209].m1) + ((clientId) * \
-       IRO[209].m2))
+       (IRO[215].base + ((portId) * IRO[215].m1) + ((clientId) * \
+       IRO[215].m2))
 #define USTORM_RX_PRODS_E2_OFFSET(qzoneId) \
-       (IRO[210].base + ((qzoneId) * IRO[210].m1))
-#define USTORM_TPA_BTR_OFFSET (IRO[207].base)
-#define USTORM_TPA_BTR_SIZE (IRO[207].size)
+       (IRO[216].base + ((qzoneId) * IRO[216].m1))
+#define USTORM_TPA_BTR_OFFSET (IRO[213].base)
+#define USTORM_TPA_BTR_SIZE (IRO[213].size)
 #define USTORM_VF_TO_PF_OFFSET(funcId) \
-       (IRO[179].base + ((funcId) * IRO[179].m1))
+       (IRO[183].base + ((funcId) * IRO[183].m1))
 #define XSTORM_AGG_INT_FINAL_CLEANUP_COMP_TYPE (IRO[67].base)
 #define XSTORM_AGG_INT_FINAL_CLEANUP_INDEX (IRO[66].base)
 #define XSTORM_ASSERT_LIST_INDEX_OFFSET        (IRO[51].base)
 #define XSTORM_FUNC_EN_OFFSET(funcId) \
        (IRO[47].base + ((funcId) * IRO[47].m1))
 #define XSTORM_ISCSI_HQ_SIZE_OFFSET(pfId) \
-       (IRO[296].base + ((pfId) * IRO[296].m1))
+       (IRO[302].base + ((pfId) * IRO[302].m1))
 #define XSTORM_ISCSI_LOCAL_MAC_ADDR0_OFFSET(pfId) \
-       (IRO[299].base + ((pfId) * IRO[299].m1))
+       (IRO[305].base + ((pfId) * IRO[305].m1))
 #define XSTORM_ISCSI_LOCAL_MAC_ADDR1_OFFSET(pfId) \
-       (IRO[300].base + ((pfId) * IRO[300].m1))
+       (IRO[306].base + ((pfId) * IRO[306].m1))
 #define XSTORM_ISCSI_LOCAL_MAC_ADDR2_OFFSET(pfId) \
-       (IRO[301].base + ((pfId) * IRO[301].m1))
+       (IRO[307].base + ((pfId) * IRO[307].m1))
 #define XSTORM_ISCSI_LOCAL_MAC_ADDR3_OFFSET(pfId) \
-       (IRO[302].base + ((pfId) * IRO[302].m1))
+       (IRO[308].base + ((pfId) * IRO[308].m1))
 #define XSTORM_ISCSI_LOCAL_MAC_ADDR4_OFFSET(pfId) \
-       (IRO[303].base + ((pfId) * IRO[303].m1))
+       (IRO[309].base + ((pfId) * IRO[309].m1))
 #define XSTORM_ISCSI_LOCAL_MAC_ADDR5_OFFSET(pfId) \
-       (IRO[304].base + ((pfId) * IRO[304].m1))
+       (IRO[310].base + ((pfId) * IRO[310].m1))
 #define XSTORM_ISCSI_LOCAL_VLAN_OFFSET(pfId) \
-       (IRO[305].base + ((pfId) * IRO[305].m1))
+       (IRO[311].base + ((pfId) * IRO[311].m1))
 #define XSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfId) \
-       (IRO[295].base + ((pfId) * IRO[295].m1))
+       (IRO[301].base + ((pfId) * IRO[301].m1))
 #define XSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfId) \
-       (IRO[294].base + ((pfId) * IRO[294].m1))
+       (IRO[300].base + ((pfId) * IRO[300].m1))
 #define XSTORM_ISCSI_PAGE_SIZE_OFFSET(pfId) \
-       (IRO[293].base + ((pfId) * IRO[293].m1))
+       (IRO[299].base + ((pfId) * IRO[299].m1))
 #define XSTORM_ISCSI_R2TQ_SIZE_OFFSET(pfId) \
-       (IRO[298].base + ((pfId) * IRO[298].m1))
+       (IRO[304].base + ((pfId) * IRO[304].m1))
 #define XSTORM_ISCSI_SQ_SIZE_OFFSET(pfId) \
-       (IRO[297].base + ((pfId) * IRO[297].m1))
+       (IRO[303].base + ((pfId) * IRO[303].m1))
 #define XSTORM_ISCSI_TCP_VARS_ADV_WND_SCL_OFFSET(pfId) \
-       (IRO[292].base + ((pfId) * IRO[292].m1))
+       (IRO[298].base + ((pfId) * IRO[298].m1))
 #define XSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(pfId) \
-       (IRO[291].base + ((pfId) * IRO[291].m1))
+       (IRO[297].base + ((pfId) * IRO[297].m1))
 #define XSTORM_ISCSI_TCP_VARS_TOS_OFFSET(pfId) \
-       (IRO[290].base + ((pfId) * IRO[290].m1))
+       (IRO[296].base + ((pfId) * IRO[296].m1))
 #define XSTORM_ISCSI_TCP_VARS_TTL_OFFSET(pfId) \
-       (IRO[289].base + ((pfId) * IRO[289].m1))
+       (IRO[295].base + ((pfId) * IRO[295].m1))
 #define XSTORM_RATE_SHAPING_PER_VN_VARS_OFFSET(pfId) \
        (IRO[44].base + ((pfId) * IRO[44].m1))
 #define XSTORM_RECORD_SLOW_PATH_OFFSET(funcId) \
 #define XSTORM_SPQ_PROD_OFFSET(funcId) \
        (IRO[31].base + ((funcId) * IRO[31].m1))
 #define XSTORM_TCP_GLOBAL_DEL_ACK_COUNTER_ENABLED_OFFSET(portId) \
-       (IRO[211].base + ((portId) * IRO[211].m1))
+       (IRO[217].base + ((portId) * IRO[217].m1))
 #define XSTORM_TCP_GLOBAL_DEL_ACK_COUNTER_MAX_COUNT_OFFSET(portId) \
-       (IRO[212].base + ((portId) * IRO[212].m1))
+       (IRO[218].base + ((portId) * IRO[218].m1))
 #define XSTORM_TCP_TX_SWS_TIMER_VAL_OFFSET(pfId) \
-       (IRO[214].base + (((pfId)>>1) * IRO[214].m1) + (((pfId)&1) * \
-       IRO[214].m2))
+       (IRO[220].base + (((pfId)>>1) * IRO[220].m1) + (((pfId)&1) * \
+       IRO[220].m2))
 #define XSTORM_VF_TO_PF_OFFSET(funcId) \
        (IRO[48].base + ((funcId) * IRO[48].m1))
 #define COMMON_ASM_INVALID_ASSERT_OPCODE 0x0
 
+/* eth hsi version */
+#define ETH_FP_HSI_VERSION (ETH_FP_HSI_VER_2)
+
 /* Ethernet Ring parameters */
 #define X_ETH_LOCAL_RING_SIZE 13
 #define FIRST_BD_IN_PKT        0
 #define XSEMI_CLK1_RESUL_CHIP (1e-3)
 
 #define SDM_TIMER_TICK_RESUL_CHIP (4 * (1e-6))
+#define TSDM_TIMER_TICK_RESUL_CHIP (1 * (1e-6))
 
 /**** END DEFINES FOR TIMERS/CLOCKS RESOLUTIONS ****/
 
index 5ba8af50c84f2bb3ebf9300c9ad8765d25a06a8d..3e0621acdf05570db85127f0da200ac80160876e 100644 (file)
@@ -2233,7 +2233,12 @@ struct shmem2_region {
        u32 reserved3;                          /* Offset 0x14C */
        u32 reserved4;                          /* Offset 0x150 */
        u32 link_attr_sync[PORT_MAX];           /* Offset 0x154 */
-       #define LINK_ATTR_SYNC_KR2_ENABLE       (1<<0)
+       #define LINK_ATTR_SYNC_KR2_ENABLE       0x00000001
+       #define LINK_SFP_EEPROM_COMP_CODE_MASK  0x0000ff00
+       #define LINK_SFP_EEPROM_COMP_CODE_SHIFT          8
+       #define LINK_SFP_EEPROM_COMP_CODE_SR    0x00001000
+       #define LINK_SFP_EEPROM_COMP_CODE_LR    0x00002000
+       #define LINK_SFP_EEPROM_COMP_CODE_LRM   0x00004000
 
        u32 reserved5[2];
        u32 reserved6[PORT_MAX];
@@ -2876,8 +2881,8 @@ struct afex_stats {
 };
 
 #define BCM_5710_FW_MAJOR_VERSION                      7
-#define BCM_5710_FW_MINOR_VERSION                      8
-#define BCM_5710_FW_REVISION_VERSION           19
+#define BCM_5710_FW_MINOR_VERSION                      10
+#define BCM_5710_FW_REVISION_VERSION           51
 #define BCM_5710_FW_ENGINEERING_VERSION                0
 #define BCM_5710_FW_COMPILE_FLAGS                      1
 
@@ -3446,6 +3451,7 @@ enum classify_rule {
        CLASSIFY_RULE_OPCODE_MAC,
        CLASSIFY_RULE_OPCODE_VLAN,
        CLASSIFY_RULE_OPCODE_PAIR,
+       CLASSIFY_RULE_OPCODE_VXLAN,
        MAX_CLASSIFY_RULE
 };
 
@@ -3475,7 +3481,8 @@ struct client_init_general_data {
        u8 func_id;
        u8 cos;
        u8 traffic_type;
-       u32 reserved0;
+       u8 fp_hsi_ver;
+       u8 reserved0[3];
 };
 
 
@@ -3545,7 +3552,9 @@ struct client_init_rx_data {
        __le16 rx_cos_mask;
        __le16 silent_vlan_value;
        __le16 silent_vlan_mask;
-       __le32 reserved6[2];
+       u8 handle_ptp_pkts_flg;
+       u8 reserved6[3];
+       __le32 reserved7;
 };
 
 /*
@@ -3576,7 +3585,7 @@ struct client_init_tx_data {
        u8 tunnel_lso_inc_ip_id;
        u8 refuse_outband_vlan_flg;
        u8 tunnel_non_lso_pcsum_location;
-       u8 reserved1;
+       u8 tunnel_non_lso_outer_ip_csum_location;
 };
 
 /*
@@ -3614,7 +3623,9 @@ struct client_update_ramrod_data {
        u8 refuse_outband_vlan_change_flg;
        u8 tx_switching_flg;
        u8 tx_switching_change_flg;
-       __le32 reserved1;
+       u8 handle_ptp_pkts_flg;
+       u8 handle_ptp_pkts_change_flg;
+       __le16 reserved1;
        __le32 echo;
 };
 
@@ -3634,6 +3645,11 @@ struct double_regpair {
        u32 regpair1_hi;
 };
 
+/* 2nd parse bd type used in ethernet tx BDs */
+enum eth_2nd_parse_bd_type {
+       ETH_2ND_PARSE_BD_TYPE_LSO_TUNNEL,
+       MAX_ETH_2ND_PARSE_BD_TYPE
+};
 
 /*
  * Ethernet address typesm used in ethernet tx BDs
@@ -3718,6 +3734,18 @@ struct eth_classify_vlan_cmd {
        __le16 vlan;
 };
 
+/*
+ * Command for adding/removing a VXLAN classification rule
+ */
+struct eth_classify_vxlan_cmd {
+       struct eth_classify_cmd_header header;
+       __le32 vni;
+       __le16 inner_mac_lsb;
+       __le16 inner_mac_mid;
+       __le16 inner_mac_msb;
+       __le16 reserved1;
+};
+
 /*
  * union for eth classification rule
  */
@@ -3725,6 +3753,7 @@ union eth_classify_rule_cmd {
        struct eth_classify_mac_cmd mac;
        struct eth_classify_vlan_cmd vlan;
        struct eth_classify_pair_cmd pair;
+       struct eth_classify_vxlan_cmd vxlan;
 };
 
 /*
@@ -3830,8 +3859,10 @@ struct eth_fast_path_rx_cqe {
 #define ETH_FAST_PATH_RX_CQE_IP_BAD_XSUM_FLG_SHIFT 4
 #define ETH_FAST_PATH_RX_CQE_L4_BAD_XSUM_FLG (0x1<<5)
 #define ETH_FAST_PATH_RX_CQE_L4_BAD_XSUM_FLG_SHIFT 5
-#define ETH_FAST_PATH_RX_CQE_RESERVED0 (0x3<<6)
-#define ETH_FAST_PATH_RX_CQE_RESERVED0_SHIFT 6
+#define ETH_FAST_PATH_RX_CQE_PTP_PKT (0x1<<6)
+#define ETH_FAST_PATH_RX_CQE_PTP_PKT_SHIFT 6
+#define ETH_FAST_PATH_RX_CQE_RESERVED0 (0x1<<7)
+#define ETH_FAST_PATH_RX_CQE_RESERVED0_SHIFT 7
        u8 status_flags;
 #define ETH_FAST_PATH_RX_CQE_RSS_HASH_TYPE (0x7<<0)
 #define ETH_FAST_PATH_RX_CQE_RSS_HASH_TYPE_SHIFT 0
@@ -3902,6 +3933,13 @@ struct eth_filter_rules_ramrod_data {
        struct eth_filter_rules_cmd rules[FILTER_RULES_COUNT];
 };
 
+/* Hsi version */
+enum eth_fp_hsi_ver {
+       ETH_FP_HSI_VER_0,
+       ETH_FP_HSI_VER_1,
+       ETH_FP_HSI_VER_2,
+       MAX_ETH_FP_HSI_VER
+};
 
 /*
  * parameters for eth classification configuration ramrod
@@ -3950,29 +3988,17 @@ struct eth_mac_addresses {
 
 /* tunneling related data */
 struct eth_tunnel_data {
-#if defined(__BIG_ENDIAN)
-       __le16 dst_mid;
-       __le16 dst_lo;
-#elif defined(__LITTLE_ENDIAN)
        __le16 dst_lo;
        __le16 dst_mid;
-#endif
-#if defined(__BIG_ENDIAN)
-       __le16 reserved0;
-       __le16 dst_hi;
-#elif defined(__LITTLE_ENDIAN)
        __le16 dst_hi;
-       __le16 reserved0;
-#endif
-#if defined(__BIG_ENDIAN)
-       u8 reserved1;
-       u8 ip_hdr_start_inner_w;
-       __le16 pseudo_csum;
-#elif defined(__LITTLE_ENDIAN)
+       __le16 fw_ip_hdr_csum;
        __le16 pseudo_csum;
        u8 ip_hdr_start_inner_w;
-       u8 reserved1;
-#endif
+       u8 flags;
+#define ETH_TUNNEL_DATA_IP_HDR_TYPE_OUTER (0x1<<0)
+#define ETH_TUNNEL_DATA_IP_HDR_TYPE_OUTER_SHIFT 0
+#define ETH_TUNNEL_DATA_RESERVED (0x7F<<1)
+#define ETH_TUNNEL_DATA_RESERVED_SHIFT 1
 };
 
 /* union for mac addresses and for tunneling data.
@@ -4059,31 +4085,41 @@ enum eth_rss_mode {
  */
 struct eth_rss_update_ramrod_data {
        u8 rss_engine_id;
-       u8 capabilities;
+       u8 rss_mode;
+       __le16 capabilities;
 #define ETH_RSS_UPDATE_RAMROD_DATA_IPV4_CAPABILITY (0x1<<0)
 #define ETH_RSS_UPDATE_RAMROD_DATA_IPV4_CAPABILITY_SHIFT 0
 #define ETH_RSS_UPDATE_RAMROD_DATA_IPV4_TCP_CAPABILITY (0x1<<1)
 #define ETH_RSS_UPDATE_RAMROD_DATA_IPV4_TCP_CAPABILITY_SHIFT 1
 #define ETH_RSS_UPDATE_RAMROD_DATA_IPV4_UDP_CAPABILITY (0x1<<2)
 #define ETH_RSS_UPDATE_RAMROD_DATA_IPV4_UDP_CAPABILITY_SHIFT 2
-#define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_CAPABILITY (0x1<<3)
-#define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_CAPABILITY_SHIFT 3
-#define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_TCP_CAPABILITY (0x1<<4)
-#define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_TCP_CAPABILITY_SHIFT 4
-#define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_UDP_CAPABILITY (0x1<<5)
-#define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_UDP_CAPABILITY_SHIFT 5
-#define ETH_RSS_UPDATE_RAMROD_DATA_EN_5_TUPLE_CAPABILITY (0x1<<6)
-#define ETH_RSS_UPDATE_RAMROD_DATA_EN_5_TUPLE_CAPABILITY_SHIFT 6
-#define ETH_RSS_UPDATE_RAMROD_DATA_UPDATE_RSS_KEY (0x1<<7)
-#define ETH_RSS_UPDATE_RAMROD_DATA_UPDATE_RSS_KEY_SHIFT 7
+#define ETH_RSS_UPDATE_RAMROD_DATA_IPV4_VXLAN_CAPABILITY (0x1<<3)
+#define ETH_RSS_UPDATE_RAMROD_DATA_IPV4_VXLAN_CAPABILITY_SHIFT 3
+#define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_CAPABILITY (0x1<<4)
+#define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_CAPABILITY_SHIFT 4
+#define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_TCP_CAPABILITY (0x1<<5)
+#define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_TCP_CAPABILITY_SHIFT 5
+#define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_UDP_CAPABILITY (0x1<<6)
+#define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_UDP_CAPABILITY_SHIFT 6
+#define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_VXLAN_CAPABILITY (0x1<<7)
+#define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_VXLAN_CAPABILITY_SHIFT 7
+#define ETH_RSS_UPDATE_RAMROD_DATA_EN_5_TUPLE_CAPABILITY (0x1<<8)
+#define ETH_RSS_UPDATE_RAMROD_DATA_EN_5_TUPLE_CAPABILITY_SHIFT 8
+#define ETH_RSS_UPDATE_RAMROD_DATA_NVGRE_KEY_ENTROPY_CAPABILITY (0x1<<9)
+#define ETH_RSS_UPDATE_RAMROD_DATA_NVGRE_KEY_ENTROPY_CAPABILITY_SHIFT 9
+#define ETH_RSS_UPDATE_RAMROD_DATA_GRE_INNER_HDRS_CAPABILITY (0x1<<10)
+#define ETH_RSS_UPDATE_RAMROD_DATA_GRE_INNER_HDRS_CAPABILITY_SHIFT 10
+#define ETH_RSS_UPDATE_RAMROD_DATA_UPDATE_RSS_KEY (0x1<<11)
+#define ETH_RSS_UPDATE_RAMROD_DATA_UPDATE_RSS_KEY_SHIFT 11
+#define ETH_RSS_UPDATE_RAMROD_DATA_RESERVED (0xF<<12)
+#define ETH_RSS_UPDATE_RAMROD_DATA_RESERVED_SHIFT 12
        u8 rss_result_mask;
-       u8 rss_mode;
-       __le16 udp_4tuple_dst_port_mask;
-       __le16 udp_4tuple_dst_port_value;
+       u8 reserved3;
+       __le16 reserved4;
        u8 indirection_table[T_ETH_INDIRECTION_TABLE_SIZE];
        __le32 rss_key[T_ETH_RSS_KEY];
        __le32 echo;
-       __le32 reserved3;
+       __le32 reserved5;
 };
 
 
@@ -4255,10 +4291,10 @@ enum eth_tunnel_lso_inc_ip_id {
 /* In case tunnel exist and L4 checksum offload,
  * the pseudo checksum location, on packet or on BD.
  */
-enum eth_tunnel_non_lso_pcsum_location {
-       PCSUM_ON_PKT,
-       PCSUM_ON_BD,
-       MAX_ETH_TUNNEL_NON_LSO_PCSUM_LOCATION
+enum eth_tunnel_non_lso_csum_location {
+       CSUM_ON_PKT,
+       CSUM_ON_BD,
+       MAX_ETH_TUNNEL_NON_LSO_CSUM_LOCATION
 };
 
 /*
@@ -4305,8 +4341,10 @@ struct eth_tx_start_bd {
        __le16 vlan_or_ethertype;
        struct eth_tx_bd_flags bd_flags;
        u8 general_data;
-#define ETH_TX_START_BD_HDR_NBDS (0xF<<0)
+#define ETH_TX_START_BD_HDR_NBDS (0x7<<0)
 #define ETH_TX_START_BD_HDR_NBDS_SHIFT 0
+#define ETH_TX_START_BD_NO_ADDED_TAGS (0x1<<3)
+#define ETH_TX_START_BD_NO_ADDED_TAGS_SHIFT 3
 #define ETH_TX_START_BD_FORCE_VLAN_MODE (0x1<<4)
 #define ETH_TX_START_BD_FORCE_VLAN_MODE_SHIFT 4
 #define ETH_TX_START_BD_PARSE_NBDS (0x3<<5)
@@ -4382,8 +4420,8 @@ struct eth_tx_parse_2nd_bd {
        __le16 global_data;
 #define ETH_TX_PARSE_2ND_BD_IP_HDR_START_OUTER_W (0xF<<0)
 #define ETH_TX_PARSE_2ND_BD_IP_HDR_START_OUTER_W_SHIFT 0
-#define ETH_TX_PARSE_2ND_BD_IP_HDR_TYPE_OUTER (0x1<<4)
-#define ETH_TX_PARSE_2ND_BD_IP_HDR_TYPE_OUTER_SHIFT 4
+#define ETH_TX_PARSE_2ND_BD_RESERVED0 (0x1<<4)
+#define ETH_TX_PARSE_2ND_BD_RESERVED0_SHIFT 4
 #define ETH_TX_PARSE_2ND_BD_LLC_SNAP_EN (0x1<<5)
 #define ETH_TX_PARSE_2ND_BD_LLC_SNAP_EN_SHIFT 5
 #define ETH_TX_PARSE_2ND_BD_NS_FLG (0x1<<6)
@@ -4392,9 +4430,14 @@ struct eth_tx_parse_2nd_bd {
 #define ETH_TX_PARSE_2ND_BD_TUNNEL_UDP_EXIST_SHIFT 7
 #define ETH_TX_PARSE_2ND_BD_IP_HDR_LEN_OUTER_W (0x1F<<8)
 #define ETH_TX_PARSE_2ND_BD_IP_HDR_LEN_OUTER_W_SHIFT 8
-#define ETH_TX_PARSE_2ND_BD_RESERVED0 (0x7<<13)
-#define ETH_TX_PARSE_2ND_BD_RESERVED0_SHIFT 13
-       __le16 reserved1;
+#define ETH_TX_PARSE_2ND_BD_RESERVED1 (0x7<<13)
+#define ETH_TX_PARSE_2ND_BD_RESERVED1_SHIFT 13
+       u8 bd_type;
+#define ETH_TX_PARSE_2ND_BD_TYPE (0xF<<0)
+#define ETH_TX_PARSE_2ND_BD_TYPE_SHIFT 0
+#define ETH_TX_PARSE_2ND_BD_RESERVED2 (0xF<<4)
+#define ETH_TX_PARSE_2ND_BD_RESERVED2_SHIFT 4
+       u8 reserved3;
        u8 tcp_flags;
 #define ETH_TX_PARSE_2ND_BD_FIN_FLG (0x1<<0)
 #define ETH_TX_PARSE_2ND_BD_FIN_FLG_SHIFT 0
@@ -4412,7 +4455,7 @@ struct eth_tx_parse_2nd_bd {
 #define ETH_TX_PARSE_2ND_BD_ECE_FLG_SHIFT 6
 #define ETH_TX_PARSE_2ND_BD_CWR_FLG (0x1<<7)
 #define ETH_TX_PARSE_2ND_BD_CWR_FLG_SHIFT 7
-       u8 reserved2;
+       u8 reserved4;
        u8 tunnel_udp_hdr_start_w;
        u8 fw_ip_hdr_to_payload_w;
        __le16 fw_ip_csum_wo_len_flags_frag;
@@ -5200,10 +5243,18 @@ struct function_start_data {
        u8 path_id;
        u8 network_cos_mode;
        u8 dmae_cmd_id;
-       u8 gre_tunnel_mode;
-       u8 gre_tunnel_rss;
-       u8 nvgre_clss_en;
-       __le16 reserved1[2];
+       u8 tunnel_mode;
+       u8 gre_tunnel_type;
+       u8 tunn_clss_en;
+       u8 inner_gre_rss_en;
+       u8 sd_accept_mf_clss_fail;
+       __le16 vxlan_dst_port;
+       __le16 sd_accept_mf_clss_fail_ethtype;
+       __le16 sd_vlan_eth_type;
+       u8 sd_vlan_force_pri_flg;
+       u8 sd_vlan_force_pri_val;
+       u8 sd_accept_mf_clss_fail_match_ethtype;
+       u8 no_added_tags;
 };
 
 struct function_update_data {
@@ -5220,12 +5271,20 @@ struct function_update_data {
        u8 tx_switch_suspend_change_flg;
        u8 tx_switch_suspend;
        u8 echo;
+       u8 update_tunn_cfg_flg;
+       u8 tunnel_mode;
+       u8 gre_tunnel_type;
+       u8 tunn_clss_en;
+       u8 inner_gre_rss_en;
+       __le16 vxlan_dst_port;
+       u8 sd_vlan_force_pri_change_flg;
+       u8 sd_vlan_force_pri_flg;
+       u8 sd_vlan_force_pri_val;
+       u8 sd_vlan_tag_change_flg;
+       u8 sd_vlan_eth_type_change_flg;
        u8 reserved1;
-       u8 update_gre_cfg_flg;
-       u8 gre_tunnel_mode;
-       u8 gre_tunnel_rss;
-       u8 nvgre_clss_en;
-       u32 reserved3;
+       __le16 sd_vlan_tag;
+       __le16 sd_vlan_eth_type;
 };
 
 /*
@@ -5254,17 +5313,9 @@ struct fw_version {
 #define __FW_VERSION_RESERVED_SHIFT 4
 };
 
-/* GRE RSS Mode */
-enum gre_rss_mode {
-       GRE_OUTER_HEADERS_RSS,
-       GRE_INNER_HEADERS_RSS,
-       NVGRE_KEY_ENTROPY_RSS,
-       MAX_GRE_RSS_MODE
-};
 
 /* GRE Tunnel Mode */
 enum gre_tunnel_type {
-       NO_GRE_TUNNEL,
        NVGRE_TUNNEL,
        L2GRE_TUNNEL,
        IPGRE_TUNNEL,
@@ -5437,6 +5488,7 @@ enum ip_ver {
  * Malicious VF error ID
  */
 enum malicious_vf_error_id {
+       MALICIOUS_VF_NO_ERROR,
        VF_PF_CHANNEL_NOT_READY,
        ETH_ILLEGAL_BD_LENGTHS,
        ETH_PACKET_TOO_SHORT,
@@ -5597,6 +5649,16 @@ struct protocol_common_spe {
        union protocol_common_specific_data data;
 };
 
+/* The data for the Set Timesync Ramrod */
+struct set_timesync_ramrod_data {
+       u8 drift_adjust_cmd;
+       u8 offset_cmd;
+       u8 add_sub_drift_adjust_value;
+       u8 drift_adjust_value;
+       u32 drift_adjust_period;
+       struct regpair offset_delta;
+};
+
 /*
  * The send queue element
  */
@@ -5719,10 +5781,38 @@ struct tstorm_vf_zone_data {
        struct regpair reserved;
 };
 
+/* Add or Subtract Value for Set Timesync Ramrod */
+enum ts_add_sub_value {
+       TS_SUB_VALUE,
+       TS_ADD_VALUE,
+       MAX_TS_ADD_SUB_VALUE
+};
 
-/*
- * zone A per-queue data
- */
+/* Drift-Adjust Commands for Set Timesync Ramrod */
+enum ts_drift_adjust_cmd {
+       TS_DRIFT_ADJUST_KEEP,
+       TS_DRIFT_ADJUST_SET,
+       TS_DRIFT_ADJUST_RESET,
+       MAX_TS_DRIFT_ADJUST_CMD
+};
+
+/* Offset Commands for Set Timesync Ramrod */
+enum ts_offset_cmd {
+       TS_OFFSET_KEEP,
+       TS_OFFSET_INC,
+       TS_OFFSET_DEC,
+       MAX_TS_OFFSET_CMD
+};
+
+/* Tunnel Mode */
+enum tunnel_mode {
+       TUNN_MODE_NONE,
+       TUNN_MODE_VXLAN,
+       TUNN_MODE_GRE,
+       MAX_TUNNEL_MODE
+};
+
+ /* zone A per-queue data */
 struct ustorm_queue_zone_data {
        struct ustorm_eth_rx_producers eth_rx_producers;
        struct regpair reserved[3];
index 53fb4fa61b405aa540239492fef2d5a4f94fa9bd..549549eaf580f79518295bd4a13234cef8520968 100644 (file)
@@ -154,15 +154,22 @@ typedef int (*read_sfp_module_eeprom_func_p)(struct bnx2x_phy *phy,
                         LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE)
 
 #define SFP_EEPROM_CON_TYPE_ADDR               0x2
+       #define SFP_EEPROM_CON_TYPE_VAL_UNKNOWN 0x0
        #define SFP_EEPROM_CON_TYPE_VAL_LC      0x7
        #define SFP_EEPROM_CON_TYPE_VAL_COPPER  0x21
        #define SFP_EEPROM_CON_TYPE_VAL_RJ45    0x22
 
 
-#define SFP_EEPROM_COMP_CODE_ADDR              0x3
-       #define SFP_EEPROM_COMP_CODE_SR_MASK    (1<<4)
-       #define SFP_EEPROM_COMP_CODE_LR_MASK    (1<<5)
-       #define SFP_EEPROM_COMP_CODE_LRM_MASK   (1<<6)
+#define SFP_EEPROM_10G_COMP_CODE_ADDR          0x3
+       #define SFP_EEPROM_10G_COMP_CODE_SR_MASK        (1<<4)
+       #define SFP_EEPROM_10G_COMP_CODE_LR_MASK        (1<<5)
+       #define SFP_EEPROM_10G_COMP_CODE_LRM_MASK       (1<<6)
+
+#define SFP_EEPROM_1G_COMP_CODE_ADDR           0x6
+       #define SFP_EEPROM_1G_COMP_CODE_SX      (1<<0)
+       #define SFP_EEPROM_1G_COMP_CODE_LX      (1<<1)
+       #define SFP_EEPROM_1G_COMP_CODE_CX      (1<<2)
+       #define SFP_EEPROM_1G_COMP_CODE_BASE_T  (1<<3)
 
 #define SFP_EEPROM_FC_TX_TECH_ADDR             0x8
        #define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE 0x4
@@ -3633,8 +3640,8 @@ static void bnx2x_warpcore_enable_AN_KR2(struct bnx2x_phy *phy,
                                 reg_set[i].val);
 
        /* Start KR2 work-around timer which handles BCM8073 link-parner */
-       vars->link_attr_sync |= LINK_ATTR_SYNC_KR2_ENABLE;
-       bnx2x_update_link_attr(params, vars->link_attr_sync);
+       params->link_attr_sync |= LINK_ATTR_SYNC_KR2_ENABLE;
+       bnx2x_update_link_attr(params, params->link_attr_sync);
 }
 
 static void bnx2x_disable_kr2(struct link_params *params,
@@ -3666,8 +3673,8 @@ static void bnx2x_disable_kr2(struct link_params *params,
        for (i = 0; i < ARRAY_SIZE(reg_set); i++)
                bnx2x_cl45_write(bp, phy, reg_set[i].devad, reg_set[i].reg,
                                 reg_set[i].val);
-       vars->link_attr_sync &= ~LINK_ATTR_SYNC_KR2_ENABLE;
-       bnx2x_update_link_attr(params, vars->link_attr_sync);
+       params->link_attr_sync &= ~LINK_ATTR_SYNC_KR2_ENABLE;
+       bnx2x_update_link_attr(params, params->link_attr_sync);
 
        vars->check_kr2_recovery_cnt = CHECK_KR2_RECOVERY_CNT;
 }
@@ -4810,7 +4817,7 @@ void bnx2x_link_status_update(struct link_params *params,
                                        ~FEATURE_CONFIG_PFC_ENABLED;
 
        if (SHMEM2_HAS(bp, link_attr_sync))
-               vars->link_attr_sync = SHMEM2_RD(bp,
+               params->link_attr_sync = SHMEM2_RD(bp,
                                                 link_attr_sync[params->port]);
 
        DP(NETIF_MSG_LINK, "link_status 0x%x  phy_link_up %x int_mask 0x%x\n",
@@ -8057,21 +8064,24 @@ static int bnx2x_get_edc_mode(struct bnx2x_phy *phy,
 {
        struct bnx2x *bp = params->bp;
        u32 sync_offset = 0, phy_idx, media_types;
-       u8 gport, val[2], check_limiting_mode = 0;
+       u8 val[SFP_EEPROM_FC_TX_TECH_ADDR + 1], check_limiting_mode = 0;
        *edc_mode = EDC_MODE_LIMITING;
        phy->media_type = ETH_PHY_UNSPECIFIED;
        /* First check for copper cable */
        if (bnx2x_read_sfp_module_eeprom(phy,
                                         params,
                                         I2C_DEV_ADDR_A0,
-                                        SFP_EEPROM_CON_TYPE_ADDR,
-                                        2,
+                                        0,
+                                        SFP_EEPROM_FC_TX_TECH_ADDR + 1,
                                         (u8 *)val) != 0) {
                DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM\n");
                return -EINVAL;
        }
-
-       switch (val[0]) {
+       params->link_attr_sync &= ~LINK_SFP_EEPROM_COMP_CODE_MASK;
+       params->link_attr_sync |= val[SFP_EEPROM_10G_COMP_CODE_ADDR] <<
+               LINK_SFP_EEPROM_COMP_CODE_SHIFT;
+       bnx2x_update_link_attr(params, params->link_attr_sync);
+       switch (val[SFP_EEPROM_CON_TYPE_ADDR]) {
        case SFP_EEPROM_CON_TYPE_VAL_COPPER:
        {
                u8 copper_module_type;
@@ -8079,17 +8089,7 @@ static int bnx2x_get_edc_mode(struct bnx2x_phy *phy,
                /* Check if its active cable (includes SFP+ module)
                 * of passive cable
                 */
-               if (bnx2x_read_sfp_module_eeprom(phy,
-                                              params,
-                                              I2C_DEV_ADDR_A0,
-                                              SFP_EEPROM_FC_TX_TECH_ADDR,
-                                              1,
-                                              &copper_module_type) != 0) {
-                       DP(NETIF_MSG_LINK,
-                               "Failed to read copper-cable-type"
-                               " from SFP+ EEPROM\n");
-                       return -EINVAL;
-               }
+               copper_module_type = val[SFP_EEPROM_FC_TX_TECH_ADDR];
 
                if (copper_module_type &
                    SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE) {
@@ -8115,16 +8115,18 @@ static int bnx2x_get_edc_mode(struct bnx2x_phy *phy,
                }
                break;
        }
+       case SFP_EEPROM_CON_TYPE_VAL_UNKNOWN:
        case SFP_EEPROM_CON_TYPE_VAL_LC:
        case SFP_EEPROM_CON_TYPE_VAL_RJ45:
                check_limiting_mode = 1;
-               if ((val[1] & (SFP_EEPROM_COMP_CODE_SR_MASK |
-                              SFP_EEPROM_COMP_CODE_LR_MASK |
-                              SFP_EEPROM_COMP_CODE_LRM_MASK)) == 0) {
+               if ((val[SFP_EEPROM_10G_COMP_CODE_ADDR] &
+                    (SFP_EEPROM_10G_COMP_CODE_SR_MASK |
+                     SFP_EEPROM_10G_COMP_CODE_LR_MASK |
+                     SFP_EEPROM_10G_COMP_CODE_LRM_MASK)) == 0) {
                        DP(NETIF_MSG_LINK, "1G SFP module detected\n");
-                       gport = params->port;
                        phy->media_type = ETH_PHY_SFP_1G_FIBER;
                        if (phy->req_line_speed != SPEED_1000) {
+                               u8 gport = params->port;
                                phy->req_line_speed = SPEED_1000;
                                if (!CHIP_IS_E1x(bp)) {
                                        gport = BP_PATH(bp) +
@@ -8134,6 +8136,12 @@ static int bnx2x_get_edc_mode(struct bnx2x_phy *phy,
                                           "Warning: Link speed was forced to 1000Mbps. Current SFP module in port %d is not compliant with 10G Ethernet\n",
                                           gport);
                        }
+                       if (val[SFP_EEPROM_1G_COMP_CODE_ADDR] &
+                           SFP_EEPROM_1G_COMP_CODE_BASE_T) {
+                               bnx2x_sfp_set_transmitter(params, phy, 0);
+                               msleep(40);
+                               bnx2x_sfp_set_transmitter(params, phy, 1);
+                       }
                } else {
                        int idx, cfg_idx = 0;
                        DP(NETIF_MSG_LINK, "10G Optic module detected\n");
@@ -8149,7 +8157,7 @@ static int bnx2x_get_edc_mode(struct bnx2x_phy *phy,
                break;
        default:
                DP(NETIF_MSG_LINK, "Unable to determine module type 0x%x !!!\n",
-                        val[0]);
+                        val[SFP_EEPROM_CON_TYPE_ADDR]);
                return -EINVAL;
        }
        sync_offset = params->shmem_base +
@@ -13507,7 +13515,7 @@ static void bnx2x_check_kr2_wa(struct link_params *params,
 
        sigdet = bnx2x_warpcore_get_sigdet(phy, params);
        if (!sigdet) {
-               if (!(vars->link_attr_sync & LINK_ATTR_SYNC_KR2_ENABLE)) {
+               if (!(params->link_attr_sync & LINK_ATTR_SYNC_KR2_ENABLE)) {
                        bnx2x_kr2_recovery(params, vars, phy);
                        DP(NETIF_MSG_LINK, "No sigdet\n");
                }
@@ -13525,7 +13533,7 @@ static void bnx2x_check_kr2_wa(struct link_params *params,
 
        /* CL73 has not begun yet */
        if (base_page == 0) {
-               if (!(vars->link_attr_sync & LINK_ATTR_SYNC_KR2_ENABLE)) {
+               if (!(params->link_attr_sync & LINK_ATTR_SYNC_KR2_ENABLE)) {
                        bnx2x_kr2_recovery(params, vars, phy);
                        DP(NETIF_MSG_LINK, "No BP\n");
                }
@@ -13541,7 +13549,7 @@ static void bnx2x_check_kr2_wa(struct link_params *params,
                            ((next_page & 0xe0) == 0x20))));
 
        /* In case KR2 is already disabled, check if we need to re-enable it */
-       if (!(vars->link_attr_sync & LINK_ATTR_SYNC_KR2_ENABLE)) {
+       if (!(params->link_attr_sync & LINK_ATTR_SYNC_KR2_ENABLE)) {
                if (!not_kr2_device) {
                        DP(NETIF_MSG_LINK, "BP=0x%x, NP=0x%x\n", base_page,
                           next_page);
index 389f5f8cb0a3c3108f2305b62c0843037ea4f72e..d9cce4c3899b7b9d388cf28a6f4bf0feece3c4b2 100644 (file)
@@ -323,6 +323,9 @@ struct link_params {
 #define LINK_FLAGS_INT_DISABLED                (1<<0)
 #define PHY_INITIALIZED                (1<<1)
        u32 lfa_base;
+
+       /* The same definitions as the shmem2 parameter */
+       u32 link_attr_sync;
 };
 
 /* Output parameters */
@@ -364,8 +367,6 @@ struct link_vars {
        u8 rx_tx_asic_rst;
        u8 turn_to_run_wc_rt;
        u16 rsrv2;
-       /* The same definitions as the shmem2 parameter */
-       u32 link_attr_sync;
 };
 
 /***********************************************************/
index c13364b6cc19177a0ed4688df3768cd8ac0dc53a..32e2444ab5e1c0621e2616fdb258d0d88ebe0e26 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/ethtool.h>
 #include <linux/mii.h>
 #include <linux/if_vlan.h>
+#include <linux/crash_dump.h>
 #include <net/ip.h>
 #include <net/ipv6.h>
 #include <net/tcp.h>
@@ -63,7 +64,6 @@
 #include "bnx2x_vfpf.h"
 #include "bnx2x_dcb.h"
 #include "bnx2x_sp.h"
-
 #include <linux/firmware.h>
 #include "bnx2x_fw_file_hdr.h"
 /* FW files */
@@ -290,6 +290,8 @@ static int bnx2x_set_storm_rx_mode(struct bnx2x *bp);
 * General service functions
 ****************************************************************************/
 
+static int bnx2x_hwtstamp_ioctl(struct bnx2x *bp, struct ifreq *ifr);
+
 static void __storm_memset_dma_mapping(struct bnx2x *bp,
                                       u32 addr, dma_addr_t mapping)
 {
@@ -523,6 +525,7 @@ int bnx2x_issue_dmae_with_comp(struct bnx2x *bp, struct dmae_command *dmae,
         * as long as this code is called both from syscall context and
         * from ndo_set_rx_mode() flow that may be called from BH.
         */
+
        spin_lock_bh(&bp->dmae_lock);
 
        /* reset completion */
@@ -551,7 +554,9 @@ int bnx2x_issue_dmae_with_comp(struct bnx2x *bp, struct dmae_command *dmae,
        }
 
 unlock:
+
        spin_unlock_bh(&bp->dmae_lock);
+
        return rc;
 }
 
@@ -646,119 +651,98 @@ static void bnx2x_write_dmae_phys_len(struct bnx2x *bp, dma_addr_t phys_addr,
        bnx2x_write_dmae(bp, phys_addr + offset, addr + offset, len);
 }
 
+enum storms {
+          XSTORM,
+          TSTORM,
+          CSTORM,
+          USTORM,
+          MAX_STORMS
+};
+
+#define STORMS_NUM 4
+#define REGS_IN_ENTRY 4
+
+static inline int bnx2x_get_assert_list_entry(struct bnx2x *bp,
+                                             enum storms storm,
+                                             int entry)
+{
+       switch (storm) {
+       case XSTORM:
+               return XSTORM_ASSERT_LIST_OFFSET(entry);
+       case TSTORM:
+               return TSTORM_ASSERT_LIST_OFFSET(entry);
+       case CSTORM:
+               return CSTORM_ASSERT_LIST_OFFSET(entry);
+       case USTORM:
+               return USTORM_ASSERT_LIST_OFFSET(entry);
+       case MAX_STORMS:
+       default:
+               BNX2X_ERR("unknown storm\n");
+       }
+       return -EINVAL;
+}
+
 static int bnx2x_mc_assert(struct bnx2x *bp)
 {
        char last_idx;
-       int i, rc = 0;
-       u32 row0, row1, row2, row3;
-
-       /* XSTORM */
-       last_idx = REG_RD8(bp, BAR_XSTRORM_INTMEM +
-                          XSTORM_ASSERT_LIST_INDEX_OFFSET);
-       if (last_idx)
-               BNX2X_ERR("XSTORM_ASSERT_LIST_INDEX 0x%x\n", last_idx);
-
-       /* print the asserts */
-       for (i = 0; i < STROM_ASSERT_ARRAY_SIZE; i++) {
-
-               row0 = REG_RD(bp, BAR_XSTRORM_INTMEM +
-                             XSTORM_ASSERT_LIST_OFFSET(i));
-               row1 = REG_RD(bp, BAR_XSTRORM_INTMEM +
-                             XSTORM_ASSERT_LIST_OFFSET(i) + 4);
-               row2 = REG_RD(bp, BAR_XSTRORM_INTMEM +
-                             XSTORM_ASSERT_LIST_OFFSET(i) + 8);
-               row3 = REG_RD(bp, BAR_XSTRORM_INTMEM +
-                             XSTORM_ASSERT_LIST_OFFSET(i) + 12);
-
-               if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) {
-                       BNX2X_ERR("XSTORM_ASSERT_INDEX 0x%x = 0x%08x 0x%08x 0x%08x 0x%08x\n",
-                                 i, row3, row2, row1, row0);
-                       rc++;
-               } else {
-                       break;
-               }
-       }
-
-       /* TSTORM */
-       last_idx = REG_RD8(bp, BAR_TSTRORM_INTMEM +
-                          TSTORM_ASSERT_LIST_INDEX_OFFSET);
-       if (last_idx)
-               BNX2X_ERR("TSTORM_ASSERT_LIST_INDEX 0x%x\n", last_idx);
-
-       /* print the asserts */
-       for (i = 0; i < STROM_ASSERT_ARRAY_SIZE; i++) {
-
-               row0 = REG_RD(bp, BAR_TSTRORM_INTMEM +
-                             TSTORM_ASSERT_LIST_OFFSET(i));
-               row1 = REG_RD(bp, BAR_TSTRORM_INTMEM +
-                             TSTORM_ASSERT_LIST_OFFSET(i) + 4);
-               row2 = REG_RD(bp, BAR_TSTRORM_INTMEM +
-                             TSTORM_ASSERT_LIST_OFFSET(i) + 8);
-               row3 = REG_RD(bp, BAR_TSTRORM_INTMEM +
-                             TSTORM_ASSERT_LIST_OFFSET(i) + 12);
-
-               if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) {
-                       BNX2X_ERR("TSTORM_ASSERT_INDEX 0x%x = 0x%08x 0x%08x 0x%08x 0x%08x\n",
-                                 i, row3, row2, row1, row0);
-                       rc++;
-               } else {
-                       break;
-               }
-       }
+       int i, j, rc = 0;
+       enum storms storm;
+       u32 regs[REGS_IN_ENTRY];
+       u32 bar_storm_intmem[STORMS_NUM] = {
+               BAR_XSTRORM_INTMEM,
+               BAR_TSTRORM_INTMEM,
+               BAR_CSTRORM_INTMEM,
+               BAR_USTRORM_INTMEM
+       };
+       u32 storm_assert_list_index[STORMS_NUM] = {
+               XSTORM_ASSERT_LIST_INDEX_OFFSET,
+               TSTORM_ASSERT_LIST_INDEX_OFFSET,
+               CSTORM_ASSERT_LIST_INDEX_OFFSET,
+               USTORM_ASSERT_LIST_INDEX_OFFSET
+       };
+       char *storms_string[STORMS_NUM] = {
+               "XSTORM",
+               "TSTORM",
+               "CSTORM",
+               "USTORM"
+       };
 
-       /* CSTORM */
-       last_idx = REG_RD8(bp, BAR_CSTRORM_INTMEM +
-                          CSTORM_ASSERT_LIST_INDEX_OFFSET);
-       if (last_idx)
-               BNX2X_ERR("CSTORM_ASSERT_LIST_INDEX 0x%x\n", last_idx);
-
-       /* print the asserts */
-       for (i = 0; i < STROM_ASSERT_ARRAY_SIZE; i++) {
-
-               row0 = REG_RD(bp, BAR_CSTRORM_INTMEM +
-                             CSTORM_ASSERT_LIST_OFFSET(i));
-               row1 = REG_RD(bp, BAR_CSTRORM_INTMEM +
-                             CSTORM_ASSERT_LIST_OFFSET(i) + 4);
-               row2 = REG_RD(bp, BAR_CSTRORM_INTMEM +
-                             CSTORM_ASSERT_LIST_OFFSET(i) + 8);
-               row3 = REG_RD(bp, BAR_CSTRORM_INTMEM +
-                             CSTORM_ASSERT_LIST_OFFSET(i) + 12);
-
-               if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) {
-                       BNX2X_ERR("CSTORM_ASSERT_INDEX 0x%x = 0x%08x 0x%08x 0x%08x 0x%08x\n",
-                                 i, row3, row2, row1, row0);
-                       rc++;
-               } else {
-                       break;
+       for (storm = XSTORM; storm < MAX_STORMS; storm++) {
+               last_idx = REG_RD8(bp, bar_storm_intmem[storm] +
+                                  storm_assert_list_index[storm]);
+               if (last_idx)
+                       BNX2X_ERR("%s_ASSERT_LIST_INDEX 0x%x\n",
+                                 storms_string[storm], last_idx);
+
+               /* print the asserts */
+               for (i = 0; i < STROM_ASSERT_ARRAY_SIZE; i++) {
+                       /* read a single assert entry */
+                       for (j = 0; j < REGS_IN_ENTRY; j++)
+                               regs[j] = REG_RD(bp, bar_storm_intmem[storm] +
+                                         bnx2x_get_assert_list_entry(bp,
+                                                                     storm,
+                                                                     i) +
+                                         sizeof(u32) * j);
+
+                       /* log entry if it contains a valid assert */
+                       if (regs[0] != COMMON_ASM_INVALID_ASSERT_OPCODE) {
+                               BNX2X_ERR("%s_ASSERT_INDEX 0x%x = 0x%08x 0x%08x 0x%08x 0x%08x\n",
+                                         storms_string[storm], i, regs[3],
+                                         regs[2], regs[1], regs[0]);
+                               rc++;
+                       } else {
+                               break;
+                       }
                }
        }
 
-       /* USTORM */
-       last_idx = REG_RD8(bp, BAR_USTRORM_INTMEM +
-                          USTORM_ASSERT_LIST_INDEX_OFFSET);
-       if (last_idx)
-               BNX2X_ERR("USTORM_ASSERT_LIST_INDEX 0x%x\n", last_idx);
-
-       /* print the asserts */
-       for (i = 0; i < STROM_ASSERT_ARRAY_SIZE; i++) {
-
-               row0 = REG_RD(bp, BAR_USTRORM_INTMEM +
-                             USTORM_ASSERT_LIST_OFFSET(i));
-               row1 = REG_RD(bp, BAR_USTRORM_INTMEM +
-                             USTORM_ASSERT_LIST_OFFSET(i) + 4);
-               row2 = REG_RD(bp, BAR_USTRORM_INTMEM +
-                             USTORM_ASSERT_LIST_OFFSET(i) + 8);
-               row3 = REG_RD(bp, BAR_USTRORM_INTMEM +
-                             USTORM_ASSERT_LIST_OFFSET(i) + 12);
-
-               if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) {
-                       BNX2X_ERR("USTORM_ASSERT_INDEX 0x%x = 0x%08x 0x%08x 0x%08x 0x%08x\n",
-                                 i, row3, row2, row1, row0);
-                       rc++;
-               } else {
-                       break;
-               }
-       }
+       BNX2X_ERR("Chip Revision: %s, FW Version: %d_%d_%d\n",
+                 CHIP_IS_E1(bp) ? "everest1" :
+                 CHIP_IS_E1H(bp) ? "everest1h" :
+                 CHIP_IS_E2(bp) ? "everest2" : "everest3",
+                 BCM_5710_FW_MAJOR_VERSION,
+                 BCM_5710_FW_MINOR_VERSION,
+                 BCM_5710_FW_REVISION_VERSION);
 
        return rc;
 }
@@ -983,6 +967,12 @@ void bnx2x_panic_dump(struct bnx2x *bp, bool disable_int)
                u32 *sb_data_p;
                struct bnx2x_fp_txdata txdata;
 
+               if (!bp->fp)
+                       break;
+
+               if (!fp->rx_cons_sb)
+                       continue;
+
                /* Rx */
                BNX2X_ERR("fp%d: rx_bd_prod(0x%x)  rx_bd_cons(0x%x)  rx_comp_prod(0x%x)  rx_comp_cons(0x%x)  *rx_cons_sb(0x%x)\n",
                          i, fp->rx_bd_prod, fp->rx_bd_cons,
@@ -995,7 +985,14 @@ void bnx2x_panic_dump(struct bnx2x *bp, bool disable_int)
                /* Tx */
                for_each_cos_in_tx_queue(fp, cos)
                {
+                       if (!fp->txdata_ptr[cos])
+                               break;
+
                        txdata = *fp->txdata_ptr[cos];
+
+                       if (!txdata.tx_cons_sb)
+                               continue;
+
                        BNX2X_ERR("fp%d: tx_pkt_prod(0x%x)  tx_pkt_cons(0x%x)  tx_bd_prod(0x%x)  tx_bd_cons(0x%x)  *tx_cons_sb(0x%x)\n",
                                  i, txdata.tx_pkt_prod,
                                  txdata.tx_pkt_cons, txdata.tx_bd_prod,
@@ -1097,6 +1094,12 @@ void bnx2x_panic_dump(struct bnx2x *bp, bool disable_int)
        for_each_valid_rx_queue(bp, i) {
                struct bnx2x_fastpath *fp = &bp->fp[i];
 
+               if (!bp->fp)
+                       break;
+
+               if (!fp->rx_cons_sb)
+                       continue;
+
                start = RX_BD(le16_to_cpu(*fp->rx_cons_sb) - 10);
                end = RX_BD(le16_to_cpu(*fp->rx_cons_sb) + 503);
                for (j = start; j != end; j = RX_BD(j + 1)) {
@@ -1130,9 +1133,19 @@ void bnx2x_panic_dump(struct bnx2x *bp, bool disable_int)
        /* Tx */
        for_each_valid_tx_queue(bp, i) {
                struct bnx2x_fastpath *fp = &bp->fp[i];
+
+               if (!bp->fp)
+                       break;
+
                for_each_cos_in_tx_queue(fp, cos) {
                        struct bnx2x_fp_txdata *txdata = fp->txdata_ptr[cos];
 
+                       if (!fp->txdata_ptr[cos])
+                               break;
+
+                       if (!txdata->tx_cons_sb)
+                               continue;
+
                        start = TX_BD(le16_to_cpu(*txdata->tx_cons_sb) - 10);
                        end = TX_BD(le16_to_cpu(*txdata->tx_cons_sb) + 245);
                        for (j = start; j != end; j = TX_BD(j + 1)) {
@@ -2071,8 +2084,6 @@ int bnx2x_get_gpio(struct bnx2x *bp, int gpio_num, u8 port)
        else
                value = 0;
 
-       DP(NETIF_MSG_LINK, "pin %d  value 0x%x\n", gpio_num, value);
-
        return value;
 }
 
@@ -4678,7 +4689,7 @@ static bool bnx2x_check_blocks_with_parity2(struct bnx2x *bp, u32 sig,
        for (i = 0; sig; i++) {
                cur_bit = (0x1UL << i);
                if (sig & cur_bit) {
-                       res |= true; /* Each bit is real error! */
+                       res = true; /* Each bit is real error! */
                        if (print) {
                                switch (cur_bit) {
                                case AEU_INPUTS_ATTN_BITS_CSEMI_PARITY_ERROR:
@@ -4757,21 +4768,21 @@ static bool bnx2x_check_blocks_with_parity3(struct bnx2x *bp, u32 sig,
                                        _print_next_block((*par_num)++,
                                                          "MCP ROM");
                                *global = true;
-                               res |= true;
+                               res = true;
                                break;
                        case AEU_INPUTS_ATTN_BITS_MCP_LATCHED_UMP_RX_PARITY:
                                if (print)
                                        _print_next_block((*par_num)++,
                                                          "MCP UMP RX");
                                *global = true;
-                               res |= true;
+                               res = true;
                                break;
                        case AEU_INPUTS_ATTN_BITS_MCP_LATCHED_UMP_TX_PARITY:
                                if (print)
                                        _print_next_block((*par_num)++,
                                                          "MCP UMP TX");
                                *global = true;
-                               res |= true;
+                               res = true;
                                break;
                        case AEU_INPUTS_ATTN_BITS_MCP_LATCHED_SCPAD_PARITY:
                                if (print)
@@ -4803,7 +4814,7 @@ static bool bnx2x_check_blocks_with_parity4(struct bnx2x *bp, u32 sig,
        for (i = 0; sig; i++) {
                cur_bit = (0x1UL << i);
                if (sig & cur_bit) {
-                       res |= true; /* Each bit is real error! */
+                       res = true; /* Each bit is real error! */
                        if (print) {
                                switch (cur_bit) {
                                case AEU_INPUTS_ATTN_BITS_PGLUE_PARITY_ERROR:
@@ -5452,6 +5463,14 @@ static void bnx2x_eq_int(struct bnx2x *bp)
                                break;
 
                        goto next_spqe;
+
+               case EVENT_RING_OPCODE_SET_TIMESYNC:
+                       DP(BNX2X_MSG_SP | BNX2X_MSG_PTP,
+                          "got set_timesync ramrod completion\n");
+                       if (f_obj->complete_cmd(bp, f_obj,
+                                               BNX2X_F_CMD_SET_TIMESYNC))
+                               break;
+                       goto next_spqe;
                }
 
                switch (opcode | bp->state) {
@@ -6102,7 +6121,7 @@ static int bnx2x_fill_accept_flags(struct bnx2x *bp, u32 rx_mode,
        }
 
        /* Set ACCEPT_ANY_VLAN as we do not enable filtering by VLAN */
-       if (bp->rx_mode != BNX2X_RX_MODE_NONE) {
+       if (rx_mode != BNX2X_RX_MODE_NONE) {
                __set_bit(BNX2X_ACCEPT_ANY_VLAN, rx_accept_flags);
                __set_bit(BNX2X_ACCEPT_ANY_VLAN, tx_accept_flags);
        }
@@ -6849,6 +6868,37 @@ static void bnx2x__common_init_phy(struct bnx2x *bp)
        bnx2x_release_phy_lock(bp);
 }
 
+static void bnx2x_config_endianity(struct bnx2x *bp, u32 val)
+{
+       REG_WR(bp, PXP2_REG_RQ_QM_ENDIAN_M, val);
+       REG_WR(bp, PXP2_REG_RQ_TM_ENDIAN_M, val);
+       REG_WR(bp, PXP2_REG_RQ_SRC_ENDIAN_M, val);
+       REG_WR(bp, PXP2_REG_RQ_CDU_ENDIAN_M, val);
+       REG_WR(bp, PXP2_REG_RQ_DBG_ENDIAN_M, val);
+
+       /* make sure this value is 0 */
+       REG_WR(bp, PXP2_REG_RQ_HC_ENDIAN_M, 0);
+
+       REG_WR(bp, PXP2_REG_RD_QM_SWAP_MODE, val);
+       REG_WR(bp, PXP2_REG_RD_TM_SWAP_MODE, val);
+       REG_WR(bp, PXP2_REG_RD_SRC_SWAP_MODE, val);
+       REG_WR(bp, PXP2_REG_RD_CDURD_SWAP_MODE, val);
+}
+
+static void bnx2x_set_endianity(struct bnx2x *bp)
+{
+#ifdef __BIG_ENDIAN
+       bnx2x_config_endianity(bp, 1);
+#else
+       bnx2x_config_endianity(bp, 0);
+#endif
+}
+
+static void bnx2x_reset_endianity(struct bnx2x *bp)
+{
+       bnx2x_config_endianity(bp, 0);
+}
+
 /**
  * bnx2x_init_hw_common - initialize the HW at the COMMON phase.
  *
@@ -6915,23 +6965,7 @@ static int bnx2x_init_hw_common(struct bnx2x *bp)
 
        bnx2x_init_block(bp, BLOCK_PXP2, PHASE_COMMON);
        bnx2x_init_pxp(bp);
-
-#ifdef __BIG_ENDIAN
-       REG_WR(bp, PXP2_REG_RQ_QM_ENDIAN_M, 1);
-       REG_WR(bp, PXP2_REG_RQ_TM_ENDIAN_M, 1);
-       REG_WR(bp, PXP2_REG_RQ_SRC_ENDIAN_M, 1);
-       REG_WR(bp, PXP2_REG_RQ_CDU_ENDIAN_M, 1);
-       REG_WR(bp, PXP2_REG_RQ_DBG_ENDIAN_M, 1);
-       /* make sure this value is 0 */
-       REG_WR(bp, PXP2_REG_RQ_HC_ENDIAN_M, 0);
-
-/*     REG_WR(bp, PXP2_REG_RD_PBF_SWAP_MODE, 1); */
-       REG_WR(bp, PXP2_REG_RD_QM_SWAP_MODE, 1);
-       REG_WR(bp, PXP2_REG_RD_TM_SWAP_MODE, 1);
-       REG_WR(bp, PXP2_REG_RD_SRC_SWAP_MODE, 1);
-       REG_WR(bp, PXP2_REG_RD_CDURD_SWAP_MODE, 1);
-#endif
-
+       bnx2x_set_endianity(bp);
        bnx2x_ilt_init_page_size(bp, INITOP_SET);
 
        if (CHIP_REV_IS_FPGA(bp) && CHIP_IS_E1H(bp))
@@ -7647,7 +7681,11 @@ static inline int bnx2x_func_switch_update(struct bnx2x *bp, int suspend)
        func_params.cmd = BNX2X_F_CMD_SWITCH_UPDATE;
 
        /* Function parameters */
-       switch_update_params->suspend = suspend;
+       __set_bit(BNX2X_F_UPDATE_TX_SWITCH_SUSPEND_CHNG,
+                 &switch_update_params->changes);
+       if (suspend)
+               __set_bit(BNX2X_F_UPDATE_TX_SWITCH_SUSPEND,
+                         &switch_update_params->changes);
 
        rc = bnx2x_func_state_change(bp, &func_params);
 
@@ -9010,7 +9048,7 @@ static int bnx2x_func_wait_started(struct bnx2x *bp)
                struct bnx2x_func_state_params func_params = {NULL};
 
                DP(NETIF_MSG_IFDOWN,
-                  "Hmmm... Unexpected function state! Forcing STARTED-->TX_ST0PPED-->STARTED\n");
+                  "Hmmm... Unexpected function state! Forcing STARTED-->TX_STOPPED-->STARTED\n");
 
                func_params.f_obj = &bp->func_obj;
                __set_bit(RAMROD_DRV_CLR_ONLY,
@@ -9029,6 +9067,48 @@ static int bnx2x_func_wait_started(struct bnx2x *bp)
        return 0;
 }
 
+static void bnx2x_disable_ptp(struct bnx2x *bp)
+{
+       int port = BP_PORT(bp);
+
+       /* Disable sending PTP packets to host */
+       REG_WR(bp, port ? NIG_REG_P1_LLH_PTP_TO_HOST :
+              NIG_REG_P0_LLH_PTP_TO_HOST, 0x0);
+
+       /* Reset PTP event detection rules */
+       REG_WR(bp, port ? NIG_REG_P1_LLH_PTP_PARAM_MASK :
+              NIG_REG_P0_LLH_PTP_PARAM_MASK, 0x7FF);
+       REG_WR(bp, port ? NIG_REG_P1_LLH_PTP_RULE_MASK :
+              NIG_REG_P0_LLH_PTP_RULE_MASK, 0x3FFF);
+       REG_WR(bp, port ? NIG_REG_P1_TLLH_PTP_PARAM_MASK :
+              NIG_REG_P0_TLLH_PTP_PARAM_MASK, 0x7FF);
+       REG_WR(bp, port ? NIG_REG_P1_TLLH_PTP_RULE_MASK :
+              NIG_REG_P0_TLLH_PTP_RULE_MASK, 0x3FFF);
+
+       /* Disable the PTP feature */
+       REG_WR(bp, port ? NIG_REG_P1_PTP_EN :
+              NIG_REG_P0_PTP_EN, 0x0);
+}
+
+/* Called during unload, to stop PTP-related stuff */
+void bnx2x_stop_ptp(struct bnx2x *bp)
+{
+       /* Cancel PTP work queue. Should be done after the Tx queues are
+        * drained to prevent additional scheduling.
+        */
+       cancel_work_sync(&bp->ptp_task);
+
+       if (bp->ptp_tx_skb) {
+               dev_kfree_skb_any(bp->ptp_tx_skb);
+               bp->ptp_tx_skb = NULL;
+       }
+
+       /* Disable PTP in HW */
+       bnx2x_disable_ptp(bp);
+
+       DP(BNX2X_MSG_PTP, "PTP stop ended successfully\n");
+}
+
 void bnx2x_chip_cleanup(struct bnx2x *bp, int unload_mode, bool keep_link)
 {
        int port = BP_PORT(bp);
@@ -9147,6 +9227,13 @@ unload_error:
 #endif
        }
 
+       /* stop_ptp should be after the Tx queues are drained to prevent
+        * scheduling to the cancelled PTP work queue. It should also be after
+        * function stop ramrod is sent, since as part of this ramrod FW access
+        * PTP registers.
+        */
+       bnx2x_stop_ptp(bp);
+
        /* Disable HW interrupts, NAPI */
        bnx2x_netif_stop(bp, 1);
        /* Delete all NAPI objects */
@@ -10052,6 +10139,8 @@ static void bnx2x_prev_unload_close_mac(struct bnx2x *bp,
 }
 
 #define BNX2X_PREV_UNDI_PROD_ADDR(p) (BAR_TSTRORM_INTMEM + 0x1508 + ((p) << 4))
+#define BNX2X_PREV_UNDI_PROD_ADDR_H(f) (BAR_TSTRORM_INTMEM + \
+                                       0x1848 + ((f) << 4))
 #define BNX2X_PREV_UNDI_RCQ(val)       ((val) & 0xffff)
 #define BNX2X_PREV_UNDI_BD(val)                ((val) >> 16 & 0xffff)
 #define BNX2X_PREV_UNDI_PROD(rcq, bd)  ((bd) << 16 | (rcq))
@@ -10059,8 +10148,6 @@ static void bnx2x_prev_unload_close_mac(struct bnx2x *bp,
 #define BCM_5710_UNDI_FW_MF_MAJOR      (0x07)
 #define BCM_5710_UNDI_FW_MF_MINOR      (0x08)
 #define BCM_5710_UNDI_FW_MF_VERS       (0x05)
-#define BNX2X_PREV_UNDI_MF_PORT(p) (BAR_TSTRORM_INTMEM + 0x150c + ((p) << 4))
-#define BNX2X_PREV_UNDI_MF_FUNC(f) (BAR_TSTRORM_INTMEM + 0x184c + ((f) << 4))
 
 static bool bnx2x_prev_is_after_undi(struct bnx2x *bp)
 {
@@ -10079,72 +10166,25 @@ static bool bnx2x_prev_is_after_undi(struct bnx2x *bp)
        return false;
 }
 
-static bool bnx2x_prev_unload_undi_fw_supports_mf(struct bnx2x *bp)
-{
-       u8 major, minor, version;
-       u32 fw;
-
-       /* Must check that FW is loaded */
-       if (!(REG_RD(bp, MISC_REG_RESET_REG_1) &
-            MISC_REGISTERS_RESET_REG_1_RST_XSEM)) {
-               BNX2X_DEV_INFO("XSEM is reset - UNDI MF FW is not loaded\n");
-               return false;
-       }
-
-       /* Read Currently loaded FW version */
-       fw = REG_RD(bp, XSEM_REG_PRAM);
-       major = fw & 0xff;
-       minor = (fw >> 0x8) & 0xff;
-       version = (fw >> 0x10) & 0xff;
-       BNX2X_DEV_INFO("Loaded FW: 0x%08x: Major 0x%02x Minor 0x%02x Version 0x%02x\n",
-                      fw, major, minor, version);
-
-       if (major > BCM_5710_UNDI_FW_MF_MAJOR)
-               return true;
-
-       if ((major == BCM_5710_UNDI_FW_MF_MAJOR) &&
-           (minor > BCM_5710_UNDI_FW_MF_MINOR))
-               return true;
-
-       if ((major == BCM_5710_UNDI_FW_MF_MAJOR) &&
-           (minor == BCM_5710_UNDI_FW_MF_MINOR) &&
-           (version >= BCM_5710_UNDI_FW_MF_VERS))
-               return true;
-
-       return false;
-}
-
-static void bnx2x_prev_unload_undi_mf(struct bnx2x *bp)
-{
-       int i;
-
-       /* Due to legacy (FW) code, the first function on each engine has a
-        * different offset macro from the rest of the functions.
-        * Setting this for all 8 functions is harmless regardless of whether
-        * this is actually a multi-function device.
-        */
-       for (i = 0; i < 2; i++)
-               REG_WR(bp, BNX2X_PREV_UNDI_MF_PORT(i), 1);
-
-       for (i = 2; i < 8; i++)
-               REG_WR(bp, BNX2X_PREV_UNDI_MF_FUNC(i - 2), 1);
-
-       BNX2X_DEV_INFO("UNDI FW (MF) set to discard\n");
-}
-
-static void bnx2x_prev_unload_undi_inc(struct bnx2x *bp, u8 port, u8 inc)
+static void bnx2x_prev_unload_undi_inc(struct bnx2x *bp, u8 inc)
 {
        u16 rcq, bd;
-       u32 tmp_reg = REG_RD(bp, BNX2X_PREV_UNDI_PROD_ADDR(port));
+       u32 addr, tmp_reg;
+
+       if (BP_FUNC(bp) < 2)
+               addr = BNX2X_PREV_UNDI_PROD_ADDR(BP_PORT(bp));
+       else
+               addr = BNX2X_PREV_UNDI_PROD_ADDR_H(BP_FUNC(bp) - 2);
 
+       tmp_reg = REG_RD(bp, addr);
        rcq = BNX2X_PREV_UNDI_RCQ(tmp_reg) + inc;
        bd = BNX2X_PREV_UNDI_BD(tmp_reg) + inc;
 
        tmp_reg = BNX2X_PREV_UNDI_PROD(rcq, bd);
-       REG_WR(bp, BNX2X_PREV_UNDI_PROD_ADDR(port), tmp_reg);
+       REG_WR(bp, addr, tmp_reg);
 
-       BNX2X_DEV_INFO("UNDI producer [%d] rings bd -> 0x%04x, rcq -> 0x%04x\n",
-                      port, bd, rcq);
+       BNX2X_DEV_INFO("UNDI producer [%d/%d][%08x] rings bd -> 0x%04x, rcq -> 0x%04x\n",
+                      BP_PORT(bp), BP_FUNC(bp), addr, bd, rcq);
 }
 
 static int bnx2x_prev_mcp_done(struct bnx2x *bp)
@@ -10383,7 +10423,6 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp)
        /* Reset should be performed after BRB is emptied */
        if (reset_reg & MISC_REGISTERS_RESET_REG_1_RST_BRB1) {
                u32 timer_count = 1000;
-               bool need_write = true;
 
                /* Close the MAC Rx to prevent BRB from filling up */
                bnx2x_prev_unload_close_mac(bp, &mac_vals);
@@ -10420,20 +10459,10 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp)
                        else
                                timer_count--;
 
-                       /* New UNDI FW supports MF and contains better
-                        * cleaning methods - might be redundant but harmless.
-                        */
-                       if (bnx2x_prev_unload_undi_fw_supports_mf(bp)) {
-                               if (need_write) {
-                                       bnx2x_prev_unload_undi_mf(bp);
-                                       need_write = false;
-                               }
-                       } else if (prev_undi) {
-                               /* If UNDI resides in memory,
-                                * manually increment it
-                                */
-                               bnx2x_prev_unload_undi_inc(bp, BP_PORT(bp), 1);
-                       }
+                       /* If UNDI resides in memory, manually increment it */
+                       if (prev_undi)
+                               bnx2x_prev_unload_undi_inc(bp, 1);
+
                        udelay(10);
                }
 
@@ -11943,7 +11972,7 @@ 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;
+       bp->disable_tpa |= is_kdump_kernel();
 
        /* Set TPA flags */
        if (bp->disable_tpa) {
@@ -12019,6 +12048,9 @@ static int bnx2x_init_bp(struct bnx2x *bp)
 
        bp->dump_preset_idx = 1;
 
+       if (CHIP_IS_E3B0(bp))
+               bp->flags |= PTP_SUPPORTED;
+
        return rc;
 }
 
@@ -12351,13 +12383,17 @@ static int bnx2x_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        struct bnx2x *bp = netdev_priv(dev);
        struct mii_ioctl_data *mdio = if_mii(ifr);
 
-       DP(NETIF_MSG_LINK, "ioctl: phy id 0x%x, reg 0x%x, val_in 0x%x\n",
-          mdio->phy_id, mdio->reg_num, mdio->val_in);
-
        if (!netif_running(dev))
                return -EAGAIN;
 
-       return mdio_mii_ioctl(&bp->mdio, mdio, cmd);
+       switch (cmd) {
+       case SIOCSHWTSTAMP:
+               return bnx2x_hwtstamp_ioctl(bp, ifr);
+       default:
+               DP(NETIF_MSG_LINK, "ioctl: phy id 0x%x, reg 0x%x, val_in 0x%x\n",
+                  mdio->phy_id, mdio->reg_num, mdio->val_in);
+               return mdio_mii_ioctl(&bp->mdio, mdio, cmd);
+       }
 }
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
@@ -13001,6 +13037,191 @@ static int set_is_vf(int chip_id)
        }
 }
 
+/* nig_tsgen registers relative address */
+#define tsgen_ctrl 0x0
+#define tsgen_freecount 0x10
+#define tsgen_synctime_t0 0x20
+#define tsgen_offset_t0 0x28
+#define tsgen_drift_t0 0x30
+#define tsgen_synctime_t1 0x58
+#define tsgen_offset_t1 0x60
+#define tsgen_drift_t1 0x68
+
+/* FW workaround for setting drift */
+static int bnx2x_send_update_drift_ramrod(struct bnx2x *bp, int drift_dir,
+                                         int best_val, int best_period)
+{
+       struct bnx2x_func_state_params func_params = {NULL};
+       struct bnx2x_func_set_timesync_params *set_timesync_params =
+               &func_params.params.set_timesync;
+
+       /* Prepare parameters for function state transitions */
+       __set_bit(RAMROD_COMP_WAIT, &func_params.ramrod_flags);
+       __set_bit(RAMROD_RETRY, &func_params.ramrod_flags);
+
+       func_params.f_obj = &bp->func_obj;
+       func_params.cmd = BNX2X_F_CMD_SET_TIMESYNC;
+
+       /* Function parameters */
+       set_timesync_params->drift_adjust_cmd = TS_DRIFT_ADJUST_SET;
+       set_timesync_params->offset_cmd = TS_OFFSET_KEEP;
+       set_timesync_params->add_sub_drift_adjust_value =
+               drift_dir ? TS_ADD_VALUE : TS_SUB_VALUE;
+       set_timesync_params->drift_adjust_value = best_val;
+       set_timesync_params->drift_adjust_period = best_period;
+
+       return bnx2x_func_state_change(bp, &func_params);
+}
+
+static int bnx2x_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
+{
+       struct bnx2x *bp = container_of(ptp, struct bnx2x, ptp_clock_info);
+       int rc;
+       int drift_dir = 1;
+       int val, period, period1, period2, dif, dif1, dif2;
+       int best_dif = BNX2X_MAX_PHC_DRIFT, best_period = 0, best_val = 0;
+
+       DP(BNX2X_MSG_PTP, "PTP adjfreq called, ppb = %d\n", ppb);
+
+       if (!netif_running(bp->dev)) {
+               DP(BNX2X_MSG_PTP,
+                  "PTP adjfreq called while the interface is down\n");
+               return -EFAULT;
+       }
+
+       if (ppb < 0) {
+               ppb = -ppb;
+               drift_dir = 0;
+       }
+
+       if (ppb == 0) {
+               best_val = 1;
+               best_period = 0x1FFFFFF;
+       } else if (ppb >= BNX2X_MAX_PHC_DRIFT) {
+               best_val = 31;
+               best_period = 1;
+       } else {
+               /* Changed not to allow val = 8, 16, 24 as these values
+                * are not supported in workaround.
+                */
+               for (val = 0; val <= 31; val++) {
+                       if ((val & 0x7) == 0)
+                               continue;
+                       period1 = val * 1000000 / ppb;
+                       period2 = period1 + 1;
+                       if (period1 != 0)
+                               dif1 = ppb - (val * 1000000 / period1);
+                       else
+                               dif1 = BNX2X_MAX_PHC_DRIFT;
+                       if (dif1 < 0)
+                               dif1 = -dif1;
+                       dif2 = ppb - (val * 1000000 / period2);
+                       if (dif2 < 0)
+                               dif2 = -dif2;
+                       dif = (dif1 < dif2) ? dif1 : dif2;
+                       period = (dif1 < dif2) ? period1 : period2;
+                       if (dif < best_dif) {
+                               best_dif = dif;
+                               best_val = val;
+                               best_period = period;
+                       }
+               }
+       }
+
+       rc = bnx2x_send_update_drift_ramrod(bp, drift_dir, best_val,
+                                           best_period);
+       if (rc) {
+               BNX2X_ERR("Failed to set drift\n");
+               return -EFAULT;
+       }
+
+       DP(BNX2X_MSG_PTP, "Configrued val = %d, period = %d\n", best_val,
+          best_period);
+
+       return 0;
+}
+
+static int bnx2x_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+       struct bnx2x *bp = container_of(ptp, struct bnx2x, ptp_clock_info);
+       u64 now;
+
+       DP(BNX2X_MSG_PTP, "PTP adjtime called, delta = %llx\n", delta);
+
+       now = timecounter_read(&bp->timecounter);
+       now += delta;
+       /* Re-init the timecounter */
+       timecounter_init(&bp->timecounter, &bp->cyclecounter, now);
+
+       return 0;
+}
+
+static int bnx2x_ptp_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
+{
+       struct bnx2x *bp = container_of(ptp, struct bnx2x, ptp_clock_info);
+       u64 ns;
+       u32 remainder;
+
+       ns = timecounter_read(&bp->timecounter);
+
+       DP(BNX2X_MSG_PTP, "PTP gettime called, ns = %llu\n", ns);
+
+       ts->tv_sec = div_u64_rem(ns, 1000000000ULL, &remainder);
+       ts->tv_nsec = remainder;
+
+       return 0;
+}
+
+static int bnx2x_ptp_settime(struct ptp_clock_info *ptp,
+                            const struct timespec *ts)
+{
+       struct bnx2x *bp = container_of(ptp, struct bnx2x, ptp_clock_info);
+       u64 ns;
+
+       ns = ts->tv_sec * 1000000000ULL;
+       ns += ts->tv_nsec;
+
+       DP(BNX2X_MSG_PTP, "PTP settime called, ns = %llu\n", ns);
+
+       /* Re-init the timecounter */
+       timecounter_init(&bp->timecounter, &bp->cyclecounter, ns);
+
+       return 0;
+}
+
+/* Enable (or disable) ancillary features of the phc subsystem */
+static int bnx2x_ptp_enable(struct ptp_clock_info *ptp,
+                           struct ptp_clock_request *rq, int on)
+{
+       struct bnx2x *bp = container_of(ptp, struct bnx2x, ptp_clock_info);
+
+       BNX2X_ERR("PHC ancillary features are not supported\n");
+       return -ENOTSUPP;
+}
+
+void bnx2x_register_phc(struct bnx2x *bp)
+{
+       /* Fill the ptp_clock_info struct and register PTP clock*/
+       bp->ptp_clock_info.owner = THIS_MODULE;
+       snprintf(bp->ptp_clock_info.name, 16, "%s", bp->dev->name);
+       bp->ptp_clock_info.max_adj = BNX2X_MAX_PHC_DRIFT; /* In PPB */
+       bp->ptp_clock_info.n_alarm = 0;
+       bp->ptp_clock_info.n_ext_ts = 0;
+       bp->ptp_clock_info.n_per_out = 0;
+       bp->ptp_clock_info.pps = 0;
+       bp->ptp_clock_info.adjfreq = bnx2x_ptp_adjfreq;
+       bp->ptp_clock_info.adjtime = bnx2x_ptp_adjtime;
+       bp->ptp_clock_info.gettime = bnx2x_ptp_gettime;
+       bp->ptp_clock_info.settime = bnx2x_ptp_settime;
+       bp->ptp_clock_info.enable = bnx2x_ptp_enable;
+
+       bp->ptp_clock = ptp_clock_register(&bp->ptp_clock_info, &bp->pdev->dev);
+       if (IS_ERR(bp->ptp_clock)) {
+               bp->ptp_clock = NULL;
+               BNX2X_ERR("PTP clock registeration failed\n");
+       }
+}
+
 static int bnx2x_init_one(struct pci_dev *pdev,
                                    const struct pci_device_id *ent)
 {
@@ -13172,6 +13393,8 @@ static int bnx2x_init_one(struct pci_dev *pdev,
                       "Unknown",
                       dev->base_addr, bp->pdev->irq, dev->dev_addr);
 
+       bnx2x_register_phc(bp);
+
        return 0;
 
 init_one_exit:
@@ -13198,6 +13421,11 @@ static void __bnx2x_remove(struct pci_dev *pdev,
                           struct bnx2x *bp,
                           bool remove_netdev)
 {
+       if (bp->ptp_clock) {
+               ptp_clock_unregister(bp->ptp_clock);
+               bp->ptp_clock = NULL;
+       }
+
        /* Delete storage MAC address */
        if (!NO_FCOE(bp)) {
                rtnl_lock();
@@ -13227,9 +13455,15 @@ static void __bnx2x_remove(struct pci_dev *pdev,
        bnx2x_iov_remove_one(bp);
 
        /* Power on: we can't let PCI layer write to us while we are in D3 */
-       if (IS_PF(bp))
+       if (IS_PF(bp)) {
                bnx2x_set_power_state(bp, PCI_D0);
 
+               /* Set endianity registers to reset values in case next driver
+                * boots in different endianty environment.
+                */
+               bnx2x_reset_endianity(bp);
+       }
+
        /* Disable MSI/MSI-X */
        bnx2x_disable_msi(bp);
 
@@ -14173,3 +14407,332 @@ int bnx2x_pretend_func(struct bnx2x *bp, u16 pretend_func_val)
        REG_RD(bp, pretend_reg);
        return 0;
 }
+
+static void bnx2x_ptp_task(struct work_struct *work)
+{
+       struct bnx2x *bp = container_of(work, struct bnx2x, ptp_task);
+       int port = BP_PORT(bp);
+       u32 val_seq;
+       u64 timestamp, ns;
+       struct skb_shared_hwtstamps shhwtstamps;
+
+       /* Read Tx timestamp registers */
+       val_seq = REG_RD(bp, port ? NIG_REG_P1_TLLH_PTP_BUF_SEQID :
+                        NIG_REG_P0_TLLH_PTP_BUF_SEQID);
+       if (val_seq & 0x10000) {
+               /* There is a valid timestamp value */
+               timestamp = REG_RD(bp, port ? NIG_REG_P1_TLLH_PTP_BUF_TS_MSB :
+                                  NIG_REG_P0_TLLH_PTP_BUF_TS_MSB);
+               timestamp <<= 32;
+               timestamp |= REG_RD(bp, port ? NIG_REG_P1_TLLH_PTP_BUF_TS_LSB :
+                                   NIG_REG_P0_TLLH_PTP_BUF_TS_LSB);
+               /* Reset timestamp register to allow new timestamp */
+               REG_WR(bp, port ? NIG_REG_P1_TLLH_PTP_BUF_SEQID :
+                      NIG_REG_P0_TLLH_PTP_BUF_SEQID, 0x10000);
+               ns = timecounter_cyc2time(&bp->timecounter, timestamp);
+
+               memset(&shhwtstamps, 0, sizeof(shhwtstamps));
+               shhwtstamps.hwtstamp = ns_to_ktime(ns);
+               skb_tstamp_tx(bp->ptp_tx_skb, &shhwtstamps);
+               dev_kfree_skb_any(bp->ptp_tx_skb);
+               bp->ptp_tx_skb = NULL;
+
+               DP(BNX2X_MSG_PTP, "Tx timestamp, timestamp cycles = %llu, ns = %llu\n",
+                  timestamp, ns);
+       } else {
+               DP(BNX2X_MSG_PTP, "There is no valid Tx timestamp yet\n");
+               /* Reschedule to keep checking for a valid timestamp value */
+               schedule_work(&bp->ptp_task);
+       }
+}
+
+void bnx2x_set_rx_ts(struct bnx2x *bp, struct sk_buff *skb)
+{
+       int port = BP_PORT(bp);
+       u64 timestamp, ns;
+
+       timestamp = REG_RD(bp, port ? NIG_REG_P1_LLH_PTP_HOST_BUF_TS_MSB :
+                           NIG_REG_P0_LLH_PTP_HOST_BUF_TS_MSB);
+       timestamp <<= 32;
+       timestamp |= REG_RD(bp, port ? NIG_REG_P1_LLH_PTP_HOST_BUF_TS_LSB :
+                           NIG_REG_P0_LLH_PTP_HOST_BUF_TS_LSB);
+
+       /* Reset timestamp register to allow new timestamp */
+       REG_WR(bp, port ? NIG_REG_P1_LLH_PTP_HOST_BUF_SEQID :
+              NIG_REG_P0_LLH_PTP_HOST_BUF_SEQID, 0x10000);
+
+       ns = timecounter_cyc2time(&bp->timecounter, timestamp);
+
+       skb_hwtstamps(skb)->hwtstamp = ns_to_ktime(ns);
+
+       DP(BNX2X_MSG_PTP, "Rx timestamp, timestamp cycles = %llu, ns = %llu\n",
+          timestamp, ns);
+}
+
+/* Read the PHC */
+static cycle_t bnx2x_cyclecounter_read(const struct cyclecounter *cc)
+{
+       struct bnx2x *bp = container_of(cc, struct bnx2x, cyclecounter);
+       int port = BP_PORT(bp);
+       u32 wb_data[2];
+       u64 phc_cycles;
+
+       REG_RD_DMAE(bp, port ? NIG_REG_TIMESYNC_GEN_REG + tsgen_synctime_t1 :
+                   NIG_REG_TIMESYNC_GEN_REG + tsgen_synctime_t0, wb_data, 2);
+       phc_cycles = wb_data[1];
+       phc_cycles = (phc_cycles << 32) + wb_data[0];
+
+       DP(BNX2X_MSG_PTP, "PHC read cycles = %llu\n", phc_cycles);
+
+       return phc_cycles;
+}
+
+static void bnx2x_init_cyclecounter(struct bnx2x *bp)
+{
+       memset(&bp->cyclecounter, 0, sizeof(bp->cyclecounter));
+       bp->cyclecounter.read = bnx2x_cyclecounter_read;
+       bp->cyclecounter.mask = CLOCKSOURCE_MASK(64);
+       bp->cyclecounter.shift = 1;
+       bp->cyclecounter.mult = 1;
+}
+
+static int bnx2x_send_reset_timesync_ramrod(struct bnx2x *bp)
+{
+       struct bnx2x_func_state_params func_params = {NULL};
+       struct bnx2x_func_set_timesync_params *set_timesync_params =
+               &func_params.params.set_timesync;
+
+       /* Prepare parameters for function state transitions */
+       __set_bit(RAMROD_COMP_WAIT, &func_params.ramrod_flags);
+       __set_bit(RAMROD_RETRY, &func_params.ramrod_flags);
+
+       func_params.f_obj = &bp->func_obj;
+       func_params.cmd = BNX2X_F_CMD_SET_TIMESYNC;
+
+       /* Function parameters */
+       set_timesync_params->drift_adjust_cmd = TS_DRIFT_ADJUST_RESET;
+       set_timesync_params->offset_cmd = TS_OFFSET_KEEP;
+
+       return bnx2x_func_state_change(bp, &func_params);
+}
+
+int bnx2x_enable_ptp_packets(struct bnx2x *bp)
+{
+       struct bnx2x_queue_state_params q_params;
+       int rc, i;
+
+       /* send queue update ramrod to enable PTP packets */
+       memset(&q_params, 0, sizeof(q_params));
+       __set_bit(RAMROD_COMP_WAIT, &q_params.ramrod_flags);
+       q_params.cmd = BNX2X_Q_CMD_UPDATE;
+       __set_bit(BNX2X_Q_UPDATE_PTP_PKTS_CHNG,
+                 &q_params.params.update.update_flags);
+       __set_bit(BNX2X_Q_UPDATE_PTP_PKTS,
+                 &q_params.params.update.update_flags);
+
+       /* send the ramrod on all the queues of the PF */
+       for_each_eth_queue(bp, i) {
+               struct bnx2x_fastpath *fp = &bp->fp[i];
+
+               /* Set the appropriate Queue object */
+               q_params.q_obj = &bnx2x_sp_obj(bp, fp).q_obj;
+
+               /* Update the Queue state */
+               rc = bnx2x_queue_state_change(bp, &q_params);
+               if (rc) {
+                       BNX2X_ERR("Failed to enable PTP packets\n");
+                       return rc;
+               }
+       }
+
+       return 0;
+}
+
+int bnx2x_configure_ptp_filters(struct bnx2x *bp)
+{
+       int port = BP_PORT(bp);
+       int rc;
+
+       if (!bp->hwtstamp_ioctl_called)
+               return 0;
+
+       switch (bp->tx_type) {
+       case HWTSTAMP_TX_ON:
+               bp->flags |= TX_TIMESTAMPING_EN;
+               REG_WR(bp, port ? NIG_REG_P1_TLLH_PTP_PARAM_MASK :
+                      NIG_REG_P0_TLLH_PTP_PARAM_MASK, 0x6AA);
+               REG_WR(bp, port ? NIG_REG_P1_TLLH_PTP_RULE_MASK :
+                      NIG_REG_P0_TLLH_PTP_RULE_MASK, 0x3EEE);
+               break;
+       case HWTSTAMP_TX_ONESTEP_SYNC:
+               BNX2X_ERR("One-step timestamping is not supported\n");
+               return -ERANGE;
+       }
+
+       switch (bp->rx_filter) {
+       case HWTSTAMP_FILTER_NONE:
+               break;
+       case HWTSTAMP_FILTER_ALL:
+       case HWTSTAMP_FILTER_SOME:
+               bp->rx_filter = HWTSTAMP_FILTER_NONE;
+               break;
+       case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
+       case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+       case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+               bp->rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
+               /* Initialize PTP detection for UDP/IPv4 events */
+               REG_WR(bp, port ? NIG_REG_P1_LLH_PTP_PARAM_MASK :
+                      NIG_REG_P0_LLH_PTP_PARAM_MASK, 0x7EE);
+               REG_WR(bp, port ? NIG_REG_P1_LLH_PTP_RULE_MASK :
+                      NIG_REG_P0_LLH_PTP_RULE_MASK, 0x3FFE);
+               break;
+       case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+       case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+       case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+               bp->rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT;
+               /* Initialize PTP detection for UDP/IPv4 or UDP/IPv6 events */
+               REG_WR(bp, port ? NIG_REG_P1_LLH_PTP_PARAM_MASK :
+                      NIG_REG_P0_LLH_PTP_PARAM_MASK, 0x7EA);
+               REG_WR(bp, port ? NIG_REG_P1_LLH_PTP_RULE_MASK :
+                      NIG_REG_P0_LLH_PTP_RULE_MASK, 0x3FEE);
+               break;
+       case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+       case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+       case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+               bp->rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT;
+               /* Initialize PTP detection L2 events */
+               REG_WR(bp, port ? NIG_REG_P1_LLH_PTP_PARAM_MASK :
+                      NIG_REG_P0_LLH_PTP_PARAM_MASK, 0x6BF);
+               REG_WR(bp, port ? NIG_REG_P1_LLH_PTP_RULE_MASK :
+                      NIG_REG_P0_LLH_PTP_RULE_MASK, 0x3EFF);
+
+               break;
+       case HWTSTAMP_FILTER_PTP_V2_EVENT:
+       case HWTSTAMP_FILTER_PTP_V2_SYNC:
+       case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+               bp->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
+               /* Initialize PTP detection L2, UDP/IPv4 or UDP/IPv6 events */
+               REG_WR(bp, port ? NIG_REG_P1_LLH_PTP_PARAM_MASK :
+                      NIG_REG_P0_LLH_PTP_PARAM_MASK, 0x6AA);
+               REG_WR(bp, port ? NIG_REG_P1_LLH_PTP_RULE_MASK :
+                      NIG_REG_P0_LLH_PTP_RULE_MASK, 0x3EEE);
+               break;
+       }
+
+       /* Indicate to FW that this PF expects recorded PTP packets */
+       rc = bnx2x_enable_ptp_packets(bp);
+       if (rc)
+               return rc;
+
+       /* Enable sending PTP packets to host */
+       REG_WR(bp, port ? NIG_REG_P1_LLH_PTP_TO_HOST :
+              NIG_REG_P0_LLH_PTP_TO_HOST, 0x1);
+
+       return 0;
+}
+
+static int bnx2x_hwtstamp_ioctl(struct bnx2x *bp, struct ifreq *ifr)
+{
+       struct hwtstamp_config config;
+       int rc;
+
+       DP(BNX2X_MSG_PTP, "HWTSTAMP IOCTL called\n");
+
+       if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
+               return -EFAULT;
+
+       DP(BNX2X_MSG_PTP, "Requested tx_type: %d, requested rx_filters = %d\n",
+          config.tx_type, config.rx_filter);
+
+       if (config.flags) {
+               BNX2X_ERR("config.flags is reserved for future use\n");
+               return -EINVAL;
+       }
+
+       bp->hwtstamp_ioctl_called = 1;
+       bp->tx_type = config.tx_type;
+       bp->rx_filter = config.rx_filter;
+
+       rc = bnx2x_configure_ptp_filters(bp);
+       if (rc)
+               return rc;
+
+       config.rx_filter = bp->rx_filter;
+
+       return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
+               -EFAULT : 0;
+}
+
+/* Configrues HW for PTP */
+static int bnx2x_configure_ptp(struct bnx2x *bp)
+{
+       int rc, port = BP_PORT(bp);
+       u32 wb_data[2];
+
+       /* Reset PTP event detection rules - will be configured in the IOCTL */
+       REG_WR(bp, port ? NIG_REG_P1_LLH_PTP_PARAM_MASK :
+              NIG_REG_P0_LLH_PTP_PARAM_MASK, 0x7FF);
+       REG_WR(bp, port ? NIG_REG_P1_LLH_PTP_RULE_MASK :
+              NIG_REG_P0_LLH_PTP_RULE_MASK, 0x3FFF);
+       REG_WR(bp, port ? NIG_REG_P1_TLLH_PTP_PARAM_MASK :
+              NIG_REG_P0_TLLH_PTP_PARAM_MASK, 0x7FF);
+       REG_WR(bp, port ? NIG_REG_P1_TLLH_PTP_RULE_MASK :
+              NIG_REG_P0_TLLH_PTP_RULE_MASK, 0x3FFF);
+
+       /* Disable PTP packets to host - will be configured in the IOCTL*/
+       REG_WR(bp, port ? NIG_REG_P1_LLH_PTP_TO_HOST :
+              NIG_REG_P0_LLH_PTP_TO_HOST, 0x0);
+
+       /* Enable the PTP feature */
+       REG_WR(bp, port ? NIG_REG_P1_PTP_EN :
+              NIG_REG_P0_PTP_EN, 0x3F);
+
+       /* Enable the free-running counter */
+       wb_data[0] = 0;
+       wb_data[1] = 0;
+       REG_WR_DMAE(bp, NIG_REG_TIMESYNC_GEN_REG + tsgen_ctrl, wb_data, 2);
+
+       /* Reset drift register (offset register is not reset) */
+       rc = bnx2x_send_reset_timesync_ramrod(bp);
+       if (rc) {
+               BNX2X_ERR("Failed to reset PHC drift register\n");
+               return -EFAULT;
+       }
+
+       /* Reset possibly old timestamps */
+       REG_WR(bp, port ? NIG_REG_P1_LLH_PTP_HOST_BUF_SEQID :
+              NIG_REG_P0_LLH_PTP_HOST_BUF_SEQID, 0x10000);
+       REG_WR(bp, port ? NIG_REG_P1_TLLH_PTP_BUF_SEQID :
+              NIG_REG_P0_TLLH_PTP_BUF_SEQID, 0x10000);
+
+       return 0;
+}
+
+/* Called during load, to initialize PTP-related stuff */
+void bnx2x_init_ptp(struct bnx2x *bp)
+{
+       int rc;
+
+       /* Configure PTP in HW */
+       rc = bnx2x_configure_ptp(bp);
+       if (rc) {
+               BNX2X_ERR("Stopping PTP initialization\n");
+               return;
+       }
+
+       /* Init work queue for Tx timestamping */
+       INIT_WORK(&bp->ptp_task, bnx2x_ptp_task);
+
+       /* Init cyclecounter and timecounter. This is done only in the first
+        * load. If done in every load, PTP application will fail when doing
+        * unload / load (e.g. MTU change) while it is running.
+        */
+       if (!bp->timecounter_init_done) {
+               bnx2x_init_cyclecounter(bp);
+               timecounter_init(&bp->timecounter, &bp->cyclecounter,
+                                ktime_to_ns(ktime_get_real()));
+               bp->timecounter_init_done = 1;
+       }
+
+       DP(BNX2X_MSG_PTP, "PTP initialization ended successfully\n");
+}
index 2beb5430b876cb8d77cec26661c51140ab2712ed..b0779d773343cbc82aa825eed3024205581ad33f 100644 (file)
 #define NIG_REG_P0_HWPFC_ENABLE                                 0x18078
 #define NIG_REG_P0_LLH_FUNC_MEM2                                0x18480
 #define NIG_REG_P0_LLH_FUNC_MEM2_ENABLE                         0x18440
+/* [RW 17] Packet TimeSync information that is buffered in 1-deep FIFOs for
+ * the host. Bits [15:0] return the sequence ID of the packet. Bit 16
+ * indicates the validity of the data in the buffer. Writing a 1 to bit 16
+ * will clear the buffer.
+ */
+#define NIG_REG_P0_LLH_PTP_HOST_BUF_SEQID                       0x1875c
+/* [R 32] Packet TimeSync information that is buffered in 1-deep FIFOs for
+ * the host. This location returns the lower 32 bits of timestamp value.
+ */
+#define NIG_REG_P0_LLH_PTP_HOST_BUF_TS_LSB                      0x18754
+/* [R 32] Packet TimeSync information that is buffered in 1-deep FIFOs for
+ * the host. This location returns the upper 32 bits of timestamp value.
+ */
+#define NIG_REG_P0_LLH_PTP_HOST_BUF_TS_MSB                      0x18758
+/* [RW 11] Mask register for the various parameters used in determining PTP
+ * packet presence. Set each bit to 1 to mask out the particular parameter.
+ * 0-IPv4 DA 0 of 224.0.1.129. 1-IPv4 DA 1 of 224.0.0.107. 2-IPv6 DA 0 of
+ * 0xFF0*:0:0:0:0:0:0:181. 3-IPv6 DA 1 of 0xFF02:0:0:0:0:0:0:6B. 4-UDP
+ * destination port 0 of 319. 5-UDP destination port 1 of 320. 6-MAC
+ * Ethertype 0 of 0x88F7. 7-configurable MAC Ethertype 1. 8-MAC DA 0 of
+ * 0x01-1B-19-00-00-00. 9-MAC DA 1 of 0x01-80-C2-00-00-0E. 10-configurable
+ * MAC DA 2. The reset default is set to mask out all parameters.
+ */
+#define NIG_REG_P0_LLH_PTP_PARAM_MASK                           0x187a0
+/* [RW 14] Mask regiser for the rules used in detecting PTP packets. Set
+ * each bit to 1 to mask out that particular rule. 0-{IPv4 DA 0; UDP DP 0} .
+ * 1-{IPv4 DA 0; UDP DP 1} . 2-{IPv4 DA 1; UDP DP 0} . 3-{IPv4 DA 1; UDP DP
+ * 1} . 4-{IPv6 DA 0; UDP DP 0} . 5-{IPv6 DA 0; UDP DP 1} . 6-{IPv6 DA 1;
+ * UDP DP 0} . 7-{IPv6 DA 1; UDP DP 1} . 8-{MAC DA 0; Ethertype 0} . 9-{MAC
+ * DA 1; Ethertype 0} . 10-{MAC DA 0; Ethertype 1} . 11-{MAC DA 1; Ethertype
+ * 1} . 12-{MAC DA 2; Ethertype 0} . 13-{MAC DA 2; Ethertype 1} . The reset
+ * default is to mask out all of the rules. Note that rules 0-3 are for IPv4
+ * packets only and require that the packet is IPv4 for the rules to match.
+ * Note that rules 4-7 are for IPv6 packets only and require that the packet
+ * is IPv6 for the rules to match.
+ */
+#define NIG_REG_P0_LLH_PTP_RULE_MASK                            0x187a4
+/* [RW 1] Set to 1 to enable PTP packets to be forwarded to the host. */
+#define NIG_REG_P0_LLH_PTP_TO_HOST                              0x187ac
 /* [RW 1] Input enable for RX MAC interface. */
 #define NIG_REG_P0_MAC_IN_EN                                    0x185ac
 /* [RW 1] Output enable for TX MAC interface */
  * priority field is extracted from the outer-most VLAN in receive packet.
  * Only COS 0 and COS 1 are supported in E2. */
 #define NIG_REG_P0_PKT_PRIORITY_TO_COS                          0x18054
+/* [RW 6] Enable for TimeSync feature. Bits [2:0] are for RX side. Bits
+ * [5:3] are for TX side. Bit 0 enables TimeSync on RX side. Bit 1 enables
+ * V1 frame format in timesync event detection on RX side. Bit 2 enables V2
+ * frame format in timesync event detection on RX side. Bit 3 enables
+ * TimeSync on TX side. Bit 4 enables V1 frame format in timesync event
+ * detection on TX side. Bit 5 enables V2 frame format in timesync event
+ * detection on TX side. Note that for HW to detect PTP packet and extract
+ * data from the packet, at least one of the version bits of that traffic
+ * direction has to be enabled.
+ */
+#define NIG_REG_P0_PTP_EN                                       0x18788
 /* [RW 16] Bit-map indicating which SAFC/PFC priorities to map to COS 0. A
  * priority is mapped to COS 0 when the corresponding mask bit is 1. More
  * than one bit may be set; allowing multiple priorities to be mapped to one
  * Ethernet header. */
 #define NIG_REG_P1_HDRS_AFTER_BASIC                             0x1818c
 #define NIG_REG_P1_LLH_FUNC_MEM2                                0x184c0
-#define NIG_REG_P1_LLH_FUNC_MEM2_ENABLE                         0x18460
+#define NIG_REG_P1_LLH_FUNC_MEM2_ENABLE                         0x18460a
+/* [RW 17] Packet TimeSync information that is buffered in 1-deep FIFOs for
+ * the host. Bits [15:0] return the sequence ID of the packet. Bit 16
+ * indicates the validity of the data in the buffer. Writing a 1 to bit 16
+ * will clear the buffer.
+ */
+#define NIG_REG_P1_LLH_PTP_HOST_BUF_SEQID                       0x18774
+/* [R 32] Packet TimeSync information that is buffered in 1-deep FIFOs for
+ * the host. This location returns the lower 32 bits of timestamp value.
+ */
+#define NIG_REG_P1_LLH_PTP_HOST_BUF_TS_LSB                      0x1876c
+/* [R 32] Packet TimeSync information that is buffered in 1-deep FIFOs for
+ * the host. This location returns the upper 32 bits of timestamp value.
+ */
+#define NIG_REG_P1_LLH_PTP_HOST_BUF_TS_MSB                      0x18770
+/* [RW 11] Mask register for the various parameters used in determining PTP
+ * packet presence. Set each bit to 1 to mask out the particular parameter.
+ * 0-IPv4 DA 0 of 224.0.1.129. 1-IPv4 DA 1 of 224.0.0.107. 2-IPv6 DA 0 of
+ * 0xFF0*:0:0:0:0:0:0:181. 3-IPv6 DA 1 of 0xFF02:0:0:0:0:0:0:6B. 4-UDP
+ * destination port 0 of 319. 5-UDP destination port 1 of 320. 6-MAC
+ * Ethertype 0 of 0x88F7. 7-configurable MAC Ethertype 1. 8-MAC DA 0 of
+ * 0x01-1B-19-00-00-00. 9-MAC DA 1 of 0x01-80-C2-00-00-0E. 10-configurable
+ * MAC DA 2. The reset default is set to mask out all parameters.
+ */
+#define NIG_REG_P1_LLH_PTP_PARAM_MASK                           0x187c8
+/* [RW 14] Mask regiser for the rules used in detecting PTP packets. Set
+ * each bit to 1 to mask out that particular rule. 0-{IPv4 DA 0; UDP DP 0} .
+ * 1-{IPv4 DA 0; UDP DP 1} . 2-{IPv4 DA 1; UDP DP 0} . 3-{IPv4 DA 1; UDP DP
+ * 1} . 4-{IPv6 DA 0; UDP DP 0} . 5-{IPv6 DA 0; UDP DP 1} . 6-{IPv6 DA 1;
+ * UDP DP 0} . 7-{IPv6 DA 1; UDP DP 1} . 8-{MAC DA 0; Ethertype 0} . 9-{MAC
+ * DA 1; Ethertype 0} . 10-{MAC DA 0; Ethertype 1} . 11-{MAC DA 1; Ethertype
+ * 1} . 12-{MAC DA 2; Ethertype 0} . 13-{MAC DA 2; Ethertype 1} . The reset
+ * default is to mask out all of the rules. Note that rules 0-3 are for IPv4
+ * packets only and require that the packet is IPv4 for the rules to match.
+ * Note that rules 4-7 are for IPv6 packets only and require that the packet
+ * is IPv6 for the rules to match.
+ */
+#define NIG_REG_P1_LLH_PTP_RULE_MASK                            0x187cc
+/* [RW 1] Set to 1 to enable PTP packets to be forwarded to the host. */
+#define NIG_REG_P1_LLH_PTP_TO_HOST                              0x187d4
 /* [RW 32] Specify the client number to be assigned to each priority of the
  * strict priority arbiter. This register specifies bits 31:0 of the 36-bit
  * value. Priority 0 is the highest priority. Bits [3:0] are for priority 0
  * priority field is extracted from the outer-most VLAN in receive packet.
  * Only COS 0 and COS 1 are supported in E2. */
 #define NIG_REG_P1_PKT_PRIORITY_TO_COS                          0x181a8
+/* [RW 6] Enable for TimeSync feature. Bits [2:0] are for RX side. Bits
+ * [5:3] are for TX side. Bit 0 enables TimeSync on RX side. Bit 1 enables
+ * V1 frame format in timesync event detection on RX side. Bit 2 enables V2
+ * frame format in timesync event detection on RX side. Bit 3 enables
+ * TimeSync on TX side. Bit 4 enables V1 frame format in timesync event
+ * detection on TX side. Bit 5 enables V2 frame format in timesync event
+ * detection on TX side. Note that for HW to detect PTP packet and extract
+ * data from the packet, at least one of the version bits of that traffic
+ * direction has to be enabled.
+ */
+#define NIG_REG_P1_PTP_EN                                       0x187b0
 /* [RW 16] Bit-map indicating which SAFC/PFC priorities to map to COS 0. A
  * priority is mapped to COS 0 when the corresponding mask bit is 1. More
  * than one bit may be set; allowing multiple priorities to be mapped to one
 #define NIG_REG_P1_RX_MACFIFO_EMPTY                             0x1858c
 /* [R 1] TLLH FIFO is empty. */
 #define NIG_REG_P1_TLLH_FIFO_EMPTY                              0x18338
+/* [RW 19] Packet TimeSync information that is buffered in 1-deep FIFOs for
+ * TX side. Bits [15:0] reflect the sequence ID of the packet. Bit 16
+ * indicates the validity of the data in the buffer. Bit 17 indicates that
+ * the sequence ID is valid and it is waiting for the TX timestamp value.
+ * Bit 18 indicates whether the timestamp is from a SW request (value of 1)
+ * or HW request (value of 0). Writing a 1 to bit 16 will clear the buffer.
+ */
+#define NIG_REG_P0_TLLH_PTP_BUF_SEQID                           0x187e0
+/* [R 32] Packet TimeSync information that is buffered in 1-deep FIFOs for
+ * MCP. This location returns the lower 32 bits of timestamp value.
+ */
+#define NIG_REG_P0_TLLH_PTP_BUF_TS_LSB                          0x187d8
+/* [R 32] Packet TimeSync information that is buffered in 1-deep FIFOs for
+ * MCP. This location returns the upper 32 bits of timestamp value.
+ */
+#define NIG_REG_P0_TLLH_PTP_BUF_TS_MSB                          0x187dc
+/* [RW 11] Mask register for the various parameters used in determining PTP
+ * packet presence. Set each bit to 1 to mask out the particular parameter.
+ * 0-IPv4 DA 0 of 224.0.1.129. 1-IPv4 DA 1 of 224.0.0.107. 2-IPv6 DA 0 of
+ * 0xFF0*:0:0:0:0:0:0:181. 3-IPv6 DA 1 of 0xFF02:0:0:0:0:0:0:6B. 4-UDP
+ * destination port 0 of 319. 5-UDP destination port 1 of 320. 6-MAC
+ * Ethertype 0 of 0x88F7. 7-configurable MAC Ethertype 1. 8-MAC DA 0 of
+ * 0x01-1B-19-00-00-00. 9-MAC DA 1 of 0x01-80-C2-00-00-0E. 10-configurable
+ * MAC DA 2. The reset default is set to mask out all parameters.
+ */
+#define NIG_REG_P0_TLLH_PTP_PARAM_MASK                          0x187f0
+/* [RW 14] Mask regiser for the rules used in detecting PTP packets. Set
+ * each bit to 1 to mask out that particular rule. 0-{IPv4 DA 0; UDP DP 0} .
+ * 1-{IPv4 DA 0; UDP DP 1} . 2-{IPv4 DA 1; UDP DP 0} . 3-{IPv4 DA 1; UDP DP
+ * 1} . 4-{IPv6 DA 0; UDP DP 0} . 5-{IPv6 DA 0; UDP DP 1} . 6-{IPv6 DA 1;
+ * UDP DP 0} . 7-{IPv6 DA 1; UDP DP 1} . 8-{MAC DA 0; Ethertype 0} . 9-{MAC
+ * DA 1; Ethertype 0} . 10-{MAC DA 0; Ethertype 1} . 11-{MAC DA 1; Ethertype
+ * 1} . 12-{MAC DA 2; Ethertype 0} . 13-{MAC DA 2; Ethertype 1} . The reset
+ * default is to mask out all of the rules.
+ */
+#define NIG_REG_P0_TLLH_PTP_RULE_MASK                           0x187f4
+/* [RW 19] Packet TimeSync information that is buffered in 1-deep FIFOs for
+ * TX side. Bits [15:0] reflect the sequence ID of the packet. Bit 16
+ * indicates the validity of the data in the buffer. Bit 17 indicates that
+ * the sequence ID is valid and it is waiting for the TX timestamp value.
+ * Bit 18 indicates whether the timestamp is from a SW request (value of 1)
+ * or HW request (value of 0). Writing a 1 to bit 16 will clear the buffer.
+ */
+#define NIG_REG_P1_TLLH_PTP_BUF_SEQID                           0x187ec
+/* [R 32] Packet TimeSync information that is buffered in 1-deep FIFOs for
+ * MCP. This location returns the lower 32 bits of timestamp value.
+ */
+#define NIG_REG_P1_TLLH_PTP_BUF_TS_LSB                          0x187e4
+/* [R 32] Packet TimeSync information that is buffered in 1-deep FIFOs for
+ * MCP. This location returns the upper 32 bits of timestamp value.
+ */
+#define NIG_REG_P1_TLLH_PTP_BUF_TS_MSB                          0x187e8
+/* [RW 11] Mask register for the various parameters used in determining PTP
+ * packet presence. Set each bit to 1 to mask out the particular parameter.
+ * 0-IPv4 DA 0 of 224.0.1.129. 1-IPv4 DA 1 of 224.0.0.107. 2-IPv6 DA 0 of
+ * 0xFF0*:0:0:0:0:0:0:181. 3-IPv6 DA 1 of 0xFF02:0:0:0:0:0:0:6B. 4-UDP
+ * destination port 0 of 319. 5-UDP destination port 1 of 320. 6-MAC
+ * Ethertype 0 of 0x88F7. 7-configurable MAC Ethertype 1. 8-MAC DA 0 of
+ * 0x01-1B-19-00-00-00. 9-MAC DA 1 of 0x01-80-C2-00-00-0E. 10-configurable
+ * MAC DA 2. The reset default is set to mask out all parameters.
+ */
+#define NIG_REG_P1_TLLH_PTP_PARAM_MASK                          0x187f8
+/* [RW 14] Mask regiser for the rules used in detecting PTP packets. Set
+ * each bit to 1 to mask out that particular rule. 0-{IPv4 DA 0; UDP DP 0} .
+ * 1-{IPv4 DA 0; UDP DP 1} . 2-{IPv4 DA 1; UDP DP 0} . 3-{IPv4 DA 1; UDP DP
+ * 1} . 4-{IPv6 DA 0; UDP DP 0} . 5-{IPv6 DA 0; UDP DP 1} . 6-{IPv6 DA 1;
+ * UDP DP 0} . 7-{IPv6 DA 1; UDP DP 1} . 8-{MAC DA 0; Ethertype 0} . 9-{MAC
+ * DA 1; Ethertype 0} . 10-{MAC DA 0; Ethertype 1} . 11-{MAC DA 1; Ethertype
+ * 1} . 12-{MAC DA 2; Ethertype 0} . 13-{MAC DA 2; Ethertype 1} . The reset
+ * default is to mask out all of the rules.
+ */
+#define NIG_REG_P1_TLLH_PTP_RULE_MASK                           0x187fc
 /* [RW 32] Specify which of the credit registers the client is to be mapped
  * to. This register specifies bits 31:0 of the 36-bit value. Bits[3:0] are
  * for client 0; bits [35:32] are for client 8. For clients that are not
    swap is equal to SPIO pin that inputs from ifmux_serdes_swap. If 1 then
    ort swap is equal to ~nig_registers_port_swap.port_swap */
 #define NIG_REG_STRAP_OVERRIDE                                  0x10398
+/* [WB 64] Addresses for TimeSync related registers in the timesync
+ * generator sub-module.
+ */
+#define NIG_REG_TIMESYNC_GEN_REG                                0x18800
 /* [RW 1] output enable for RX_XCM0 IF */
 #define NIG_REG_XCM0_OUT_EN                                     0x100f0
 /* [RW 1] output enable for RX_XCM1 IF */
index b1936044767aca73bc494609095ae2cc4fef55f0..19d0c1152434e4d8e75a71510dadae8e16c25ae1 100644 (file)
@@ -4019,6 +4019,7 @@ static int bnx2x_setup_rss(struct bnx2x *bp,
        struct bnx2x_raw_obj *r = &o->raw;
        struct eth_rss_update_ramrod_data *data =
                (struct eth_rss_update_ramrod_data *)(r->rdata);
+       u16 caps = 0;
        u8 rss_mode = 0;
        int rc;
 
@@ -4042,28 +4043,34 @@ static int bnx2x_setup_rss(struct bnx2x *bp,
 
        /* RSS capabilities */
        if (test_bit(BNX2X_RSS_IPV4, &p->rss_flags))
-               data->capabilities |=
-                       ETH_RSS_UPDATE_RAMROD_DATA_IPV4_CAPABILITY;
+               caps |= ETH_RSS_UPDATE_RAMROD_DATA_IPV4_CAPABILITY;
 
        if (test_bit(BNX2X_RSS_IPV4_TCP, &p->rss_flags))
-               data->capabilities |=
-                       ETH_RSS_UPDATE_RAMROD_DATA_IPV4_TCP_CAPABILITY;
+               caps |= ETH_RSS_UPDATE_RAMROD_DATA_IPV4_TCP_CAPABILITY;
 
        if (test_bit(BNX2X_RSS_IPV4_UDP, &p->rss_flags))
-               data->capabilities |=
-                       ETH_RSS_UPDATE_RAMROD_DATA_IPV4_UDP_CAPABILITY;
+               caps |= ETH_RSS_UPDATE_RAMROD_DATA_IPV4_UDP_CAPABILITY;
 
        if (test_bit(BNX2X_RSS_IPV6, &p->rss_flags))
-               data->capabilities |=
-                       ETH_RSS_UPDATE_RAMROD_DATA_IPV6_CAPABILITY;
+               caps |= ETH_RSS_UPDATE_RAMROD_DATA_IPV6_CAPABILITY;
 
        if (test_bit(BNX2X_RSS_IPV6_TCP, &p->rss_flags))
-               data->capabilities |=
-                       ETH_RSS_UPDATE_RAMROD_DATA_IPV6_TCP_CAPABILITY;
+               caps |= ETH_RSS_UPDATE_RAMROD_DATA_IPV6_TCP_CAPABILITY;
 
        if (test_bit(BNX2X_RSS_IPV6_UDP, &p->rss_flags))
-               data->capabilities |=
-                       ETH_RSS_UPDATE_RAMROD_DATA_IPV6_UDP_CAPABILITY;
+               caps |= ETH_RSS_UPDATE_RAMROD_DATA_IPV6_UDP_CAPABILITY;
+
+       if (test_bit(BNX2X_RSS_GRE_INNER_HDRS, &p->rss_flags))
+               caps |= ETH_RSS_UPDATE_RAMROD_DATA_GRE_INNER_HDRS_CAPABILITY;
+
+       /* RSS keys */
+       if (test_bit(BNX2X_RSS_SET_SRCH, &p->rss_flags)) {
+               memcpy(&data->rss_key[0], &p->rss_key[0],
+                      sizeof(data->rss_key));
+               caps |= ETH_RSS_UPDATE_RAMROD_DATA_UPDATE_RSS_KEY;
+       }
+
+       data->capabilities = cpu_to_le16(caps);
 
        /* Hashing mask */
        data->rss_result_mask = p->rss_result_mask;
@@ -4084,13 +4091,6 @@ static int bnx2x_setup_rss(struct bnx2x *bp,
        if (netif_msg_ifup(bp))
                bnx2x_debug_print_ind_table(bp, p);
 
-       /* RSS keys */
-       if (test_bit(BNX2X_RSS_SET_SRCH, &p->rss_flags)) {
-               memcpy(&data->rss_key[0], &p->rss_key[0],
-                      sizeof(data->rss_key));
-               data->capabilities |= ETH_RSS_UPDATE_RAMROD_DATA_UPDATE_RSS_KEY;
-       }
-
        /* 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
@@ -4336,6 +4336,8 @@ static void bnx2x_q_fill_init_general_data(struct bnx2x *bp,
                test_bit(BNX2X_Q_FLG_FCOE, flags) ?
                LLFC_TRAFFIC_TYPE_FCOE : LLFC_TRAFFIC_TYPE_NW;
 
+       gen_data->fp_hsi_ver = ETH_FP_HSI_VERSION;
+
        DP(BNX2X_MSG_SP, "flags: active %d, cos %d, stats en %d\n",
           gen_data->activate_flg, gen_data->cos, gen_data->statistics_en_flg);
 }
@@ -4357,12 +4359,13 @@ static void bnx2x_q_fill_init_tx_data(struct bnx2x_queue_sp_obj *o,
                test_bit(BNX2X_Q_FLG_ANTI_SPOOF, flags);
        tx_data->force_default_pri_flg =
                test_bit(BNX2X_Q_FLG_FORCE_DEFAULT_PRI, flags);
-
+       tx_data->refuse_outband_vlan_flg =
+               test_bit(BNX2X_Q_FLG_REFUSE_OUTBAND_VLAN, flags);
        tx_data->tunnel_lso_inc_ip_id =
                test_bit(BNX2X_Q_FLG_TUN_INC_INNER_IP_ID, flags);
        tx_data->tunnel_non_lso_pcsum_location =
-               test_bit(BNX2X_Q_FLG_PCSUM_ON_PKT, flags) ? PCSUM_ON_PKT :
-                                                                 PCSUM_ON_BD;
+               test_bit(BNX2X_Q_FLG_PCSUM_ON_PKT, flags) ? CSUM_ON_PKT :
+                                                           CSUM_ON_BD;
 
        tx_data->tx_status_block_id = params->fw_sb_id;
        tx_data->tx_sb_index_number = params->sb_cq_index;
@@ -4722,6 +4725,12 @@ static void bnx2x_q_fill_update_data(struct bnx2x *bp,
        data->tx_switching_change_flg =
                test_bit(BNX2X_Q_UPDATE_TX_SWITCHING_CHNG,
                         &params->update_flags);
+
+       /* PTP */
+       data->handle_ptp_pkts_flg =
+               test_bit(BNX2X_Q_UPDATE_PTP_PKTS, &params->update_flags);
+       data->handle_ptp_pkts_change_flg =
+               test_bit(BNX2X_Q_UPDATE_PTP_PKTS_CHNG, &params->update_flags);
 }
 
 static inline int bnx2x_q_send_update(struct bnx2x *bp,
@@ -5376,6 +5385,10 @@ static int bnx2x_func_chk_transition(struct bnx2x *bp,
                         (!test_bit(BNX2X_F_CMD_STOP, &o->pending)))
                        next_state = BNX2X_F_STATE_STARTED;
 
+               else if ((cmd == BNX2X_F_CMD_SET_TIMESYNC) &&
+                        (!test_bit(BNX2X_F_CMD_STOP, &o->pending)))
+                       next_state = BNX2X_F_STATE_STARTED;
+
                else if (cmd == BNX2X_F_CMD_TX_STOP)
                        next_state = BNX2X_F_STATE_TX_STOPPED;
 
@@ -5385,6 +5398,10 @@ static int bnx2x_func_chk_transition(struct bnx2x *bp,
                    (!test_bit(BNX2X_F_CMD_STOP, &o->pending)))
                        next_state = BNX2X_F_STATE_TX_STOPPED;
 
+               else if ((cmd == BNX2X_F_CMD_SET_TIMESYNC) &&
+                        (!test_bit(BNX2X_F_CMD_STOP, &o->pending)))
+                       next_state = BNX2X_F_STATE_TX_STOPPED;
+
                else if (cmd == BNX2X_F_CMD_TX_START)
                        next_state = BNX2X_F_STATE_STARTED;
 
@@ -5652,8 +5669,11 @@ static inline int bnx2x_func_send_start(struct bnx2x *bp,
        rdata->sd_vlan_tag      = cpu_to_le16(start_params->sd_vlan_tag);
        rdata->path_id          = BP_PATH(bp);
        rdata->network_cos_mode = start_params->network_cos_mode;
-       rdata->gre_tunnel_mode  = start_params->gre_tunnel_mode;
-       rdata->gre_tunnel_rss   = start_params->gre_tunnel_rss;
+       rdata->tunnel_mode      = start_params->tunnel_mode;
+       rdata->gre_tunnel_type  = start_params->gre_tunnel_type;
+       rdata->inner_gre_rss_en = start_params->inner_gre_rss_en;
+       rdata->vxlan_dst_port   = cpu_to_le16(4789);
+       rdata->sd_vlan_eth_type = cpu_to_le16(0x8100);
 
        /* No need for an explicit memory barrier here as long we would
         * need to ensure the ordering of writing to the SPQ element
@@ -5680,8 +5700,28 @@ static inline int bnx2x_func_send_switch_update(struct bnx2x *bp,
        memset(rdata, 0, sizeof(*rdata));
 
        /* Fill the ramrod data with provided parameters */
-       rdata->tx_switch_suspend_change_flg = 1;
-       rdata->tx_switch_suspend = switch_update_params->suspend;
+       if (test_bit(BNX2X_F_UPDATE_TX_SWITCH_SUSPEND_CHNG,
+                    &switch_update_params->changes)) {
+               rdata->tx_switch_suspend_change_flg = 1;
+               rdata->tx_switch_suspend =
+                       test_bit(BNX2X_F_UPDATE_TX_SWITCH_SUSPEND,
+                                &switch_update_params->changes);
+       }
+
+       if (test_bit(BNX2X_F_UPDATE_TUNNEL_CFG_CHNG,
+                    &switch_update_params->changes)) {
+               rdata->update_tunn_cfg_flg = 1;
+               if (test_bit(BNX2X_F_UPDATE_TUNNEL_CLSS_EN,
+                            &switch_update_params->changes))
+                       rdata->tunn_clss_en = 1;
+               if (test_bit(BNX2X_F_UPDATE_TUNNEL_INNER_GRE_RSS_EN,
+                            &switch_update_params->changes))
+                       rdata->inner_gre_rss_en = 1;
+               rdata->tunnel_mode = switch_update_params->tunnel_mode;
+               rdata->gre_tunnel_type = switch_update_params->gre_tunnel_type;
+               rdata->vxlan_dst_port = cpu_to_le16(4789);
+       }
+
        rdata->echo = SWITCH_UPDATE;
 
        /* No need for an explicit memory barrier here as long as we
@@ -5817,6 +5857,42 @@ static inline int bnx2x_func_send_tx_start(struct bnx2x *bp,
                             U64_LO(data_mapping), NONE_CONNECTION_TYPE);
 }
 
+static inline
+int bnx2x_func_send_set_timesync(struct bnx2x *bp,
+                                struct bnx2x_func_state_params *params)
+{
+       struct bnx2x_func_sp_obj *o = params->f_obj;
+       struct set_timesync_ramrod_data *rdata =
+               (struct set_timesync_ramrod_data *)o->rdata;
+       dma_addr_t data_mapping = o->rdata_mapping;
+       struct bnx2x_func_set_timesync_params *set_timesync_params =
+               &params->params.set_timesync;
+
+       memset(rdata, 0, sizeof(*rdata));
+
+       /* Fill the ramrod data with provided parameters */
+       rdata->drift_adjust_cmd = set_timesync_params->drift_adjust_cmd;
+       rdata->offset_cmd = set_timesync_params->offset_cmd;
+       rdata->add_sub_drift_adjust_value =
+               set_timesync_params->add_sub_drift_adjust_value;
+       rdata->drift_adjust_value = set_timesync_params->drift_adjust_value;
+       rdata->drift_adjust_period = set_timesync_params->drift_adjust_period;
+       rdata->offset_delta.lo =
+               cpu_to_le32(U64_LO(set_timesync_params->offset_delta));
+       rdata->offset_delta.hi =
+               cpu_to_le32(U64_HI(set_timesync_params->offset_delta));
+
+       DP(BNX2X_MSG_SP, "Set timesync command params: drift_cmd = %d, offset_cmd = %d, add_sub_drift = %d, drift_val = %d, drift_period = %d, offset_lo = %d, offset_hi = %d\n",
+          rdata->drift_adjust_cmd, rdata->offset_cmd,
+          rdata->add_sub_drift_adjust_value, rdata->drift_adjust_value,
+          rdata->drift_adjust_period, rdata->offset_delta.lo,
+          rdata->offset_delta.hi);
+
+       return bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_SET_TIMESYNC, 0,
+                            U64_HI(data_mapping),
+                            U64_LO(data_mapping), NONE_CONNECTION_TYPE);
+}
+
 static int bnx2x_func_send_cmd(struct bnx2x *bp,
                               struct bnx2x_func_state_params *params)
 {
@@ -5839,6 +5915,8 @@ static int bnx2x_func_send_cmd(struct bnx2x *bp,
                return bnx2x_func_send_tx_start(bp, params);
        case BNX2X_F_CMD_SWITCH_UPDATE:
                return bnx2x_func_send_switch_update(bp, params);
+       case BNX2X_F_CMD_SET_TIMESYNC:
+               return bnx2x_func_send_set_timesync(bp, params);
        default:
                BNX2X_ERR("Unknown command: %d\n", params->cmd);
                return -EINVAL;
index 718ecd2946616195cc92d53bd2f6498d525f14fe..21c8f6fb89e557b6ac98748c6c3a14943e584f70 100644 (file)
@@ -711,6 +711,7 @@ enum {
        BNX2X_RSS_IPV6,
        BNX2X_RSS_IPV6_TCP,
        BNX2X_RSS_IPV6_UDP,
+       BNX2X_RSS_GRE_INNER_HDRS,
 };
 
 struct bnx2x_config_rss_params {
@@ -769,7 +770,9 @@ enum {
        BNX2X_Q_UPDATE_SILENT_VLAN_REM_CHNG,
        BNX2X_Q_UPDATE_SILENT_VLAN_REM,
        BNX2X_Q_UPDATE_TX_SWITCHING_CHNG,
-       BNX2X_Q_UPDATE_TX_SWITCHING
+       BNX2X_Q_UPDATE_TX_SWITCHING,
+       BNX2X_Q_UPDATE_PTP_PKTS_CHNG,
+       BNX2X_Q_UPDATE_PTP_PKTS,
 };
 
 /* Allowed Queue states */
@@ -831,6 +834,7 @@ enum {
        BNX2X_Q_FLG_ANTI_SPOOF,
        BNX2X_Q_FLG_SILENT_VLAN_REM,
        BNX2X_Q_FLG_FORCE_DEFAULT_PRI,
+       BNX2X_Q_FLG_REFUSE_OUTBAND_VLAN,
        BNX2X_Q_FLG_PCSUM_ON_PKT,
        BNX2X_Q_FLG_TUN_INC_INNER_IP_ID
 };
@@ -851,6 +855,10 @@ enum bnx2x_q_type {
 #define BNX2X_MULTI_TX_COS                     3 /* Maximum possible */
 
 #define MAC_PAD (ALIGN(ETH_ALEN, sizeof(u32)) - ETH_ALEN)
+/* DMAE channel to be used by FW for timesync workaroun. A driver that sends
+ * timesync-related ramrods must not use this DMAE command ID.
+ */
+#define FW_DMAE_CMD_ID 6
 
 struct bnx2x_queue_init_params {
        struct {
@@ -1085,6 +1093,16 @@ struct bnx2x_queue_sp_obj {
 };
 
 /********************** Function state update *********************************/
+
+/* UPDATE command options */
+enum {
+       BNX2X_F_UPDATE_TX_SWITCH_SUSPEND_CHNG,
+       BNX2X_F_UPDATE_TX_SWITCH_SUSPEND,
+       BNX2X_F_UPDATE_TUNNEL_CFG_CHNG,
+       BNX2X_F_UPDATE_TUNNEL_CLSS_EN,
+       BNX2X_F_UPDATE_TUNNEL_INNER_GRE_RSS_EN,
+};
+
 /* Allowed Function states */
 enum bnx2x_func_state {
        BNX2X_F_STATE_RESET,
@@ -1105,6 +1123,7 @@ enum bnx2x_func_cmd {
        BNX2X_F_CMD_TX_STOP,
        BNX2X_F_CMD_TX_START,
        BNX2X_F_CMD_SWITCH_UPDATE,
+       BNX2X_F_CMD_SET_TIMESYNC,
        BNX2X_F_CMD_MAX,
 };
 
@@ -1146,18 +1165,25 @@ struct bnx2x_func_start_params {
        /* Function cos mode */
        u8 network_cos_mode;
 
-       /* NVGRE classification enablement */
-       u8 nvgre_clss_en;
+       /* TUNN_MODE_NONE/TUNN_MODE_VXLAN/TUNN_MODE_GRE */
+       u8 tunnel_mode;
 
-       /* NO_GRE_TUNNEL/NVGRE_TUNNEL/L2GRE_TUNNEL/IPGRE_TUNNEL */
-       u8 gre_tunnel_mode;
+       /* tunneling classification enablement */
+       u8 tunn_clss_en;
 
-       /* GRE_OUTER_HEADERS_RSS/GRE_INNER_HEADERS_RSS/NVGRE_KEY_ENTROPY_RSS */
-       u8 gre_tunnel_rss;
+       /* NVGRE_TUNNEL/L2GRE_TUNNEL/IPGRE_TUNNEL */
+       u8 gre_tunnel_type;
+
+       /* Enables Inner GRE RSS on the function, depends on the client RSS
+        * capailities
+        */
+       u8 inner_gre_rss_en;
 };
 
 struct bnx2x_func_switch_update_params {
-       u8 suspend;
+       unsigned long changes; /* BNX2X_F_UPDATE_XX bits */
+       u8 tunnel_mode;
+       u8 gre_tunnel_type;
 };
 
 struct bnx2x_func_afex_update_params {
@@ -1172,6 +1198,7 @@ struct bnx2x_func_afex_viflists_params {
        u8 afex_vif_list_command;
        u8 func_to_clear;
 };
+
 struct bnx2x_func_tx_start_params {
        struct priority_cos traffic_type_to_priority_cos[MAX_TRAFFIC_TYPES];
        u8 dcb_enabled;
@@ -1179,6 +1206,24 @@ struct bnx2x_func_tx_start_params {
        u8 dont_add_pri_0_en;
 };
 
+struct bnx2x_func_set_timesync_params {
+       /* Reset, set or keep the current drift value */
+       u8 drift_adjust_cmd;
+
+       /* Dec, inc or keep the current offset */
+       u8 offset_cmd;
+
+       /* Drift value direction */
+       u8 add_sub_drift_adjust_value;
+
+       /* Drift, period and offset values to be used according to the commands
+        * above.
+        */
+       u8 drift_adjust_value;
+       u32 drift_adjust_period;
+       u64 offset_delta;
+};
+
 struct bnx2x_func_state_params {
        struct bnx2x_func_sp_obj *f_obj;
 
@@ -1197,6 +1242,7 @@ struct bnx2x_func_state_params {
                struct bnx2x_func_afex_update_params afex_update;
                struct bnx2x_func_afex_viflists_params afex_viflists;
                struct bnx2x_func_tx_start_params tx_start;
+               struct bnx2x_func_set_timesync_params set_timesync;
        } params;
 };
 
index 662310c5f4e98c4f7d7cdda3d0062969f13ddd5b..c88b20af87dff2e6613215520eeff5920b438b0f 100644 (file)
@@ -1125,7 +1125,7 @@ static int bnx2x_ari_enabled(struct pci_dev *dev)
        return dev->bus->self && dev->bus->self->ari_enabled;
 }
 
-static void
+static int
 bnx2x_get_vf_igu_cam_info(struct bnx2x *bp)
 {
        int sb_id;
@@ -1150,6 +1150,7 @@ bnx2x_get_vf_igu_cam_info(struct bnx2x *bp)
                   GET_FIELD((val), IGU_REG_MAPPING_MEMORY_VECTOR));
        }
        DP(BNX2X_MSG_IOV, "vf_sbs_pool is %d\n", BP_VFDB(bp)->vf_sbs_pool);
+       return BP_VFDB(bp)->vf_sbs_pool;
 }
 
 static void __bnx2x_iov_free_vfdb(struct bnx2x *bp)
@@ -1314,15 +1315,17 @@ int bnx2x_iov_init_one(struct bnx2x *bp, int int_mode_param,
        }
 
        /* re-read the IGU CAM for VFs - index and abs_vfid must be set */
-       bnx2x_get_vf_igu_cam_info(bp);
+       if (!bnx2x_get_vf_igu_cam_info(bp)) {
+               BNX2X_ERR("No entries in IGU CAM for vfs\n");
+               err = -EINVAL;
+               goto failed;
+       }
 
        /* allocate the queue arrays for all VFs */
        bp->vfdb->vfqs = kzalloc(
                BNX2X_MAX_NUM_VF_QUEUES * sizeof(struct bnx2x_vf_queue),
                GFP_KERNEL);
 
-       DP(BNX2X_MSG_IOV, "bp->vfdb->vfqs was %p\n", bp->vfdb->vfqs);
-
        if (!bp->vfdb->vfqs) {
                BNX2X_ERR("failed to allocate vf queue array\n");
                err = -ENOMEM;
@@ -1349,9 +1352,7 @@ void bnx2x_iov_remove_one(struct bnx2x *bp)
        if (!IS_SRIOV(bp))
                return;
 
-       DP(BNX2X_MSG_IOV, "about to call disable sriov\n");
-       pci_disable_sriov(bp->pdev);
-       DP(BNX2X_MSG_IOV, "sriov disabled\n");
+       bnx2x_disable_sriov(bp);
 
        /* disable access to all VFs */
        for (vf_idx = 0; vf_idx < bp->vfdb->sriov.total; vf_idx++) {
@@ -1985,21 +1986,6 @@ void bnx2x_iov_adjust_stats_req(struct bnx2x *bp)
        bp->fw_stats_req->hdr.cmd_num = bp->fw_stats_num + stats_count;
 }
 
-static inline
-struct bnx2x_virtf *__vf_from_stat_id(struct bnx2x *bp, u8 stat_id)
-{
-       int i;
-       struct bnx2x_virtf *vf = NULL;
-
-       for_each_vf(bp, i) {
-               vf = BP_VF(bp, i);
-               if (stat_id >= vf->igu_base_id &&
-                   stat_id < vf->igu_base_id + vf_sb_count(vf))
-                       break;
-       }
-       return vf;
-}
-
 /* VF API helpers */
 static void bnx2x_vf_qtbl_set_q(struct bnx2x *bp, u8 abs_vfid, u8 qid,
                                u8 enable)
@@ -2362,12 +2348,6 @@ int bnx2x_vf_release(struct bnx2x *bp, struct bnx2x_virtf *vf)
        return rc;
 }
 
-static inline void bnx2x_vf_get_sbdf(struct bnx2x *bp,
-                             struct bnx2x_virtf *vf, u32 *sbdf)
-{
-       *sbdf = vf->devfn | (vf->bus << 8);
-}
-
 void bnx2x_lock_vf_pf_channel(struct bnx2x *bp, struct bnx2x_virtf *vf,
                              enum channel_tlvs tlv)
 {
@@ -2416,7 +2396,7 @@ void bnx2x_unlock_vf_pf_channel(struct bnx2x *bp, struct bnx2x_virtf *vf,
 
        /* log the unlock */
        DP(BNX2X_MSG_IOV, "VF[%d]: vf pf channel unlocked by %d\n",
-          vf->abs_vfid, vf->op_current);
+          vf->abs_vfid, current_tlv);
 }
 
 static int bnx2x_set_pf_tx_switching(struct bnx2x *bp, bool enable)
@@ -2501,7 +2481,7 @@ int bnx2x_sriov_configure(struct pci_dev *dev, int num_vfs_param)
        bp->requested_nr_virtfn = num_vfs_param;
        if (num_vfs_param == 0) {
                bnx2x_set_pf_tx_switching(bp, false);
-               pci_disable_sriov(dev);
+               bnx2x_disable_sriov(bp);
                return 0;
        } else {
                return bnx2x_enable_sriov(bp);
@@ -2614,6 +2594,12 @@ void bnx2x_pf_set_vfs_vlan(struct bnx2x *bp)
 
 void bnx2x_disable_sriov(struct bnx2x *bp)
 {
+       if (pci_vfs_assigned(bp->pdev)) {
+               DP(BNX2X_MSG_IOV,
+                  "Unloading driver while VFs are assigned - VFs will not be deallocated\n");
+               return;
+       }
+
        pci_disable_sriov(bp->pdev);
 }
 
@@ -2628,7 +2614,7 @@ static int bnx2x_vf_op_prep(struct bnx2x *bp, int vfidx,
        }
 
        if (!IS_SRIOV(bp)) {
-               BNX2X_ERR("sriov is disabled - can't utilize iov-realted functionality\n");
+               BNX2X_ERR("sriov is disabled - can't utilize iov-related functionality\n");
                return -EINVAL;
        }
 
index ca1055f3d8afda852f10412d2f551cc05b257848..01bafa4ac04589364ef092e2bd5a31231e42a5f7 100644 (file)
@@ -299,7 +299,8 @@ struct bnx2x_vfdb {
 #define BP_VFDB(bp)            ((bp)->vfdb)
        /* vf array */
        struct bnx2x_virtf      *vfs;
-#define BP_VF(bp, idx)         (&((bp)->vfdb->vfs[idx]))
+#define BP_VF(bp, idx)         ((BP_VFDB(bp) && (bp)->vfdb->vfs) ? \
+                                       &((bp)->vfdb->vfs[idx]) : NULL)
 #define bnx2x_vf(bp, idx, var) ((bp)->vfdb->vfs[idx].var)
 
        /* queue array - for all vfs */
index ca47665f94bf76fd6c9b2c1eb920b5aba7743124..d1608297c773746237a8faf3697277afcbe45918 100644 (file)
@@ -137,7 +137,7 @@ static void bnx2x_storm_stats_post(struct bnx2x *bp)
                        cpu_to_le16(bp->stats_counter++);
 
                DP(BNX2X_MSG_STATS, "Sending statistics ramrod %d\n",
-                       bp->fw_stats_req->hdr.drv_stats_counter);
+                  le16_to_cpu(bp->fw_stats_req->hdr.drv_stats_counter));
 
                /* adjust the ramrod to include VF queues statistics */
                bnx2x_iov_adjust_stats_req(bp);
@@ -200,7 +200,7 @@ static void bnx2x_hw_stats_post(struct bnx2x *bp)
        }
 }
 
-static int bnx2x_stats_comp(struct bnx2x *bp)
+static void bnx2x_stats_comp(struct bnx2x *bp)
 {
        u32 *stats_comp = bnx2x_sp(bp, stats_comp);
        int cnt = 10;
@@ -214,7 +214,6 @@ static int bnx2x_stats_comp(struct bnx2x *bp)
                cnt--;
                usleep_range(1000, 2000);
        }
-       return 1;
 }
 
 /*
@@ -1630,6 +1629,11 @@ void bnx2x_stats_init(struct bnx2x *bp)
        int /*abs*/port = BP_PORT(bp);
        int mb_idx = BP_FW_MB_IDX(bp);
 
+       if (IS_VF(bp)) {
+               bnx2x_memset_stats(bp);
+               return;
+       }
+
        bp->stats_pending = 0;
        bp->executer_idx = 0;
        bp->stats_counter = 0;
index 54e0427a9ee601b2a5e499a01c1e05218ffde368..b1d9c44aa56c919732721207d88163cda8080a53 100644 (file)
@@ -583,7 +583,6 @@ int bnx2x_vfpf_setup_q(struct bnx2x *bp, struct bnx2x_fastpath *fp,
        flags |= VFPF_QUEUE_FLG_STATS;
        flags |= VFPF_QUEUE_FLG_CACHE_ALIGN;
        flags |= VFPF_QUEUE_FLG_VLAN;
-       DP(NETIF_MSG_IFUP, "vlan removal enabled\n");
 
        /* Common */
        req->vf_qid = fp_idx;
@@ -952,14 +951,6 @@ static void storm_memset_vf_mbx_valid(struct bnx2x *bp, u16 abs_fid)
        REG_WR8(bp, addr, 1);
 }
 
-static inline void bnx2x_set_vf_mbxs_valid(struct bnx2x *bp)
-{
-       int i;
-
-       for_each_vf(bp, i)
-               storm_memset_vf_mbx_valid(bp, bnx2x_vf(bp, i, abs_vfid));
-}
-
 /* enable vf_pf mailbox (aka vf-pf-channel) */
 void bnx2x_vf_enable_mbx(struct bnx2x *bp, u8 abs_vfid)
 {
index 27861a6c7ca55966048b4cb94b0b92a0dde1d269..23f23c97c2ad7b9fa52b8d589b1627a560635f92 100644 (file)
@@ -31,7 +31,7 @@
 #include <linux/if_vlan.h>
 #include <linux/prefetch.h>
 #include <linux/random.h>
-#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
+#if IS_ENABLED(CONFIG_VLAN_8021Q)
 #define BCM_VLAN 1
 #endif
 #include <net/ip.h>
@@ -383,7 +383,7 @@ static int cnic_iscsi_nl_msg_recv(struct cnic_dev *dev, u32 msg_type,
                        break;
 
                rcu_read_lock();
-               if (!rcu_dereference(cp->ulp_ops[CNIC_ULP_L4])) {
+               if (!rcu_access_pointer(cp->ulp_ops[CNIC_ULP_L4])) {
                        rc = -ENODEV;
                        rcu_read_unlock();
                        break;
@@ -527,7 +527,7 @@ int cnic_unregister_driver(int ulp_type)
        list_for_each_entry(dev, &cnic_dev_list, list) {
                struct cnic_local *cp = dev->cnic_priv;
 
-               if (rcu_dereference(cp->ulp_ops[ulp_type])) {
+               if (rcu_access_pointer(cp->ulp_ops[ulp_type])) {
                        pr_err("%s: Type %d still has devices registered\n",
                               __func__, ulp_type);
                        read_unlock(&cnic_dev_lock);
@@ -575,7 +575,7 @@ static int cnic_register_device(struct cnic_dev *dev, int ulp_type,
                mutex_unlock(&cnic_lock);
                return -EAGAIN;
        }
-       if (rcu_dereference(cp->ulp_ops[ulp_type])) {
+       if (rcu_access_pointer(cp->ulp_ops[ulp_type])) {
                pr_err("%s: Type %d has already been registered to this device\n",
                       __func__, ulp_type);
                mutex_unlock(&cnic_lock);
@@ -3685,7 +3685,7 @@ static int cnic_get_v4_route(struct sockaddr_in *dst_addr,
 static int cnic_get_v6_route(struct sockaddr_in6 *dst_addr,
                             struct dst_entry **dst)
 {
-#if defined(CONFIG_IPV6) || (defined(CONFIG_IPV6_MODULE) && defined(MODULE))
+#if IS_ENABLED(CONFIG_IPV6)
        struct flowi6 fl6;
 
        memset(&fl6, 0, sizeof(fl6));
index 3ac5d23454a8dae9b2e618205d14dc91d822f1fe..cb77ae93d89a120591afc700ae4650d4f4002291 100644 (file)
@@ -11617,6 +11617,12 @@ static int tg3_open(struct net_device *dev)
        struct tg3 *tp = netdev_priv(dev);
        int err;
 
+       if (tp->pcierr_recovery) {
+               netdev_err(dev, "Failed to open device. PCI error recovery "
+                          "in progress\n");
+               return -EAGAIN;
+       }
+
        if (tp->fw_needed) {
                err = tg3_request_firmware(tp);
                if (tg3_asic_rev(tp) == ASIC_REV_57766) {
@@ -11674,6 +11680,12 @@ static int tg3_close(struct net_device *dev)
 {
        struct tg3 *tp = netdev_priv(dev);
 
+       if (tp->pcierr_recovery) {
+               netdev_err(dev, "Failed to close device. PCI error recovery "
+                          "in progress\n");
+               return -EAGAIN;
+       }
+
        tg3_ptp_fini(tp);
 
        tg3_stop(tp);
@@ -17561,6 +17573,7 @@ static int tg3_init_one(struct pci_dev *pdev,
        tp->rx_mode = TG3_DEF_RX_MODE;
        tp->tx_mode = TG3_DEF_TX_MODE;
        tp->irq_sync = 1;
+       tp->pcierr_recovery = false;
 
        if (tg3_debug > 0)
                tp->msg_enable = tg3_debug;
@@ -18071,6 +18084,8 @@ static pci_ers_result_t tg3_io_error_detected(struct pci_dev *pdev,
 
        rtnl_lock();
 
+       tp->pcierr_recovery = true;
+
        /* We probably don't have netdev yet */
        if (!netdev || !netif_running(netdev))
                goto done;
@@ -18195,6 +18210,7 @@ static void tg3_io_resume(struct pci_dev *pdev)
        tg3_phy_start(tp);
 
 done:
+       tp->pcierr_recovery = false;
        rtnl_unlock();
 }
 
index 461accaf0aa40242c3756880dd6659371cdfe5f0..31c9f829595384cb843e299c6b51054101d8f6c6 100644 (file)
@@ -3407,6 +3407,7 @@ struct tg3 {
 
        struct device                   *hwmon_dev;
        bool                            link_up;
+       bool                            pcierr_recovery;
 };
 
 /* Accessor macros for chip and asic attributes
index ff8cae5e2535b6e068159180105f84b2ff922b1d..ffc92a41d75be550d27698af6ca3e600d9a146fe 100644 (file)
@@ -2506,7 +2506,7 @@ bnad_tso_prepare(struct bnad *bnad, struct sk_buff *skb)
         * For TSO, the TCP checksum field is seeded with pseudo-header sum
         * excluding the length field.
         */
-       if (skb->protocol == htons(ETH_P_IP)) {
+       if (vlan_get_protocol(skb) == htons(ETH_P_IP)) {
                struct iphdr *iph = ip_hdr(skb);
 
                /* Do we really need these? */
@@ -2870,12 +2870,13 @@ bnad_txq_wi_prepare(struct bnad *bnad, struct bna_tcb *tcb,
                }
 
                if (skb->ip_summed == CHECKSUM_PARTIAL) {
+                       __be16 net_proto = vlan_get_protocol(skb);
                        u8 proto = 0;
 
-                       if (skb->protocol == htons(ETH_P_IP))
+                       if (net_proto == htons(ETH_P_IP))
                                proto = ip_hdr(skb)->protocol;
 #ifdef NETIF_F_IPV6_CSUM
-                       else if (skb->protocol == htons(ETH_P_IPV6)) {
+                       else if (net_proto == htons(ETH_P_IPV6)) {
                                /* nexthdr may not be TCP immediately. */
                                proto = ipv6_hdr(skb)->nexthdr;
                        }
index 184a063bed5fa59bbdc705e29355134a2d31d731..07d2201530d26c85e26cf0987553451acad936a6 100644 (file)
@@ -1,6 +1,7 @@
 config NET_CALXEDA_XGMAC
        tristate "Calxeda 1G/10G XGMAC Ethernet driver"
        depends on HAS_IOMEM && HAS_DMA
+       depends on ARCH_HIGHBANK || COMPILE_TEST
        select CRC32
        help
          This is the driver for the XGMAC Ethernet IP block found on Calxeda
index d57282172ea5497610dbb27185b41869372b9f13..c067b7888ac4fac6c174d3063406d087dcd530bb 100644 (file)
@@ -652,6 +652,7 @@ struct adapter {
        struct tid_info tids;
        void **tid_release_head;
        spinlock_t tid_release_lock;
+       struct workqueue_struct *workq;
        struct work_struct tid_release_task;
        struct work_struct db_full_task;
        struct work_struct db_drop_task;
index 1afee70ce856c884f4c4a8ee3595e4302c731d32..d6a9a0bc94f33ae490df4d4be839afa90c8060ba 100644 (file)
@@ -643,8 +643,6 @@ static int set_rxmode(struct net_device *dev, int mtu, bool sleep_ok)
        return ret;
 }
 
-static struct workqueue_struct *workq;
-
 /**
  *     link_start - enable a port
  *     @dev: the port to enable
@@ -1255,7 +1253,9 @@ freeout:  t4_free_sge_resources(adap);
                        goto freeout;
        }
 
-       t4_write_reg(adap, MPS_TRC_RSS_CONTROL,
+       t4_write_reg(adap, is_t4(adap->params.chip) ?
+                               MPS_TRC_RSS_CONTROL :
+                               MPS_T5_TRC_RSS_CONTROL,
                     RSSCONTROL(netdev2pinfo(adap->port[0])->tx_chan) |
                     QUEUENUMBER(s->ethrxq[0].rspq.abs_id));
        return 0;
@@ -1763,7 +1763,8 @@ static void get_regs(struct net_device *dev, struct ethtool_regs *regs,
                0xd004, 0xd03c,
                0xdfc0, 0xdfe0,
                0xe000, 0xea7c,
-               0xf000, 0x11190,
+               0xf000, 0x11110,
+               0x11118, 0x11190,
                0x19040, 0x1906c,
                0x19078, 0x19080,
                0x1908c, 0x19124,
@@ -1970,7 +1971,8 @@ static void get_regs(struct net_device *dev, struct ethtool_regs *regs,
                0xd004, 0xd03c,
                0xdfc0, 0xdfe0,
                0xe000, 0x11088,
-               0x1109c, 0x1117c,
+               0x1109c, 0x11110,
+               0x11118, 0x1117c,
                0x11190, 0x11204,
                0x19040, 0x1906c,
                0x19078, 0x19080,
@@ -3340,7 +3342,7 @@ static void cxgb4_queue_tid_release(struct tid_info *t, unsigned int chan,
        adap->tid_release_head = (void **)((uintptr_t)p | chan);
        if (!adap->tid_release_task_busy) {
                adap->tid_release_task_busy = true;
-               queue_work(workq, &adap->tid_release_task);
+               queue_work(adap->workq, &adap->tid_release_task);
        }
        spin_unlock_bh(&adap->tid_release_lock);
 }
@@ -4140,7 +4142,7 @@ void t4_db_full(struct adapter *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);
+               queue_work(adap->workq, &adap->db_full_task);
        }
 }
 
@@ -4150,7 +4152,7 @@ void t4_db_dropped(struct adapter *adap)
                disable_dbs(adap);
                notify_rdma_uld(adap, CXGB4_CONTROL_DB_FULL);
        }
-       queue_work(workq, &adap->db_drop_task);
+       queue_work(adap->workq, &adap->db_drop_task);
 }
 
 static void uld_attach(struct adapter *adap, unsigned int uld)
@@ -4388,7 +4390,6 @@ static int cxgb4_inet6addr_handler(struct notifier_block *this,
                 * bond. We need to find such different adapters and add clip
                 * in all of them only once.
                 */
-               read_lock(&bond->lock);
                bond_for_each_slave(bond, slave, iter) {
                        if (!first_pdev) {
                                ret = clip_add(slave->dev, ifa, event);
@@ -4402,7 +4403,6 @@ static int cxgb4_inet6addr_handler(struct notifier_block *this,
                                   to_pci_dev(slave->dev->dev.parent))
                                        ret = clip_add(slave->dev, ifa, event);
                }
-               read_unlock(&bond->lock);
        } else
                ret = clip_add(ifa->idev->dev, ifa, event);
 
@@ -5957,7 +5957,8 @@ static int adap_init0(struct adapter *adap)
                params[3] = FW_PARAM_PFVF(CQ_END);
                params[4] = FW_PARAM_PFVF(OCQ_START);
                params[5] = FW_PARAM_PFVF(OCQ_END);
-               ret = t4_query_params(adap, 0, 0, 0, 6, params, val);
+               ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 6, params,
+                                     val);
                if (ret < 0)
                        goto bye;
                adap->vres.qp.start = val[0];
@@ -5969,7 +5970,8 @@ static int adap_init0(struct adapter *adap)
 
                params[0] = FW_PARAM_DEV(MAXORDIRD_QP);
                params[1] = FW_PARAM_DEV(MAXIRD_ADAPTER);
-               ret = t4_query_params(adap, 0, 0, 0, 2, params, val);
+               ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 2, params,
+                                     val);
                if (ret < 0) {
                        adap->params.max_ordird_qp = 8;
                        adap->params.max_ird_adapter = 32 * adap->tids.ntids;
@@ -6517,6 +6519,12 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto out_disable_device;
        }
 
+       adapter->workq = create_singlethread_workqueue("cxgb4");
+       if (!adapter->workq) {
+               err = -ENOMEM;
+               goto out_free_adapter;
+       }
+
        /* PCI device has been enabled */
        adapter->flags |= DEV_ENABLED;
 
@@ -6715,6 +6723,9 @@ sriov:
  out_unmap_bar0:
        iounmap(adapter->regs);
  out_free_adapter:
+       if (adapter->workq)
+               destroy_workqueue(adapter->workq);
+
        kfree(adapter);
  out_disable_device:
        pci_disable_pcie_error_reporting(pdev);
@@ -6736,6 +6747,11 @@ static void remove_one(struct pci_dev *pdev)
        if (adapter) {
                int i;
 
+               /* Tear down per-adapter Work Queue first since it can contain
+                * references to our adapter data structure.
+                */
+               destroy_workqueue(adapter->workq);
+
                if (is_offload(adapter))
                        detach_ulds(adapter);
 
@@ -6788,20 +6804,14 @@ static int __init cxgb4_init_module(void)
 {
        int ret;
 
-       workq = create_singlethread_workqueue("cxgb4");
-       if (!workq)
-               return -ENOMEM;
-
        /* Debugfs support is optional, just warn if this fails */
        cxgb4_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
        if (!cxgb4_debugfs_root)
                pr_warn("could not create debugfs entry, continuing\n");
 
        ret = pci_register_driver(&cxgb4_driver);
-       if (ret < 0) {
+       if (ret < 0)
                debugfs_remove(cxgb4_debugfs_root);
-               destroy_workqueue(workq);
-       }
 
        register_inet6addr_notifier(&cxgb4_inet6addr_notifier);
 
@@ -6813,8 +6823,6 @@ static void __exit cxgb4_cleanup_module(void)
        unregister_inet6addr_notifier(&cxgb4_inet6addr_notifier);
        pci_unregister_driver(&cxgb4_driver);
        debugfs_remove(cxgb4_debugfs_root);  /* NULL ok */
-       flush_workqueue(workq);
-       destroy_workqueue(workq);
 }
 
 module_init(cxgb4_init_module);
index b0bba32d69d5dfd51eb56cfa6a6e9d5d63f5fe62..d22d728d4e5cb748321d9c86c4ad473a814d0831 100644 (file)
@@ -2303,7 +2303,8 @@ int t4_sge_alloc_eth_txq(struct adapter *adap, struct sge_eth_txq *txq,
                            FW_EQ_ETH_CMD_PFN(adap->fn) | FW_EQ_ETH_CMD_VFN(0));
        c.alloc_to_len16 = htonl(FW_EQ_ETH_CMD_ALLOC |
                                 FW_EQ_ETH_CMD_EQSTART | FW_LEN16(c));
-       c.viid_pkd = htonl(FW_EQ_ETH_CMD_VIID(pi->viid));
+       c.viid_pkd = htonl(FW_EQ_ETH_CMD_AUTOEQUEQE |
+                          FW_EQ_ETH_CMD_VIID(pi->viid));
        c.fetchszm_to_iqid = htonl(FW_EQ_ETH_CMD_HOSTFCMODE(2) |
                                   FW_EQ_ETH_CMD_PCIECHN(pi->tx_chan) |
                                   FW_EQ_ETH_CMD_FETCHRO(1) |
index a853133d8db826029ac042006e89c6d99348f2d7..41d04462b72eb158f7699c38000e6331291d2447 100644 (file)
@@ -167,6 +167,34 @@ void t4_hw_pci_read_cfg4(struct adapter *adap, int reg, u32 *val)
        t4_write_reg(adap, PCIE_CFG_SPACE_REQ, 0);
 }
 
+/*
+ * t4_report_fw_error - report firmware error
+ * @adap: the adapter
+ *
+ * The adapter firmware can indicate error conditions to the host.
+ * If the firmware has indicated an error, print out the reason for
+ * the firmware error.
+ */
+static void t4_report_fw_error(struct adapter *adap)
+{
+       static const char *const reason[] = {
+               "Crash",                        /* PCIE_FW_EVAL_CRASH */
+               "During Device Preparation",    /* PCIE_FW_EVAL_PREP */
+               "During Device Configuration",  /* PCIE_FW_EVAL_CONF */
+               "During Device Initialization", /* PCIE_FW_EVAL_INIT */
+               "Unexpected Event",             /* PCIE_FW_EVAL_UNEXPECTEDEVENT */
+               "Insufficient Airflow",         /* PCIE_FW_EVAL_OVERHEAT */
+               "Device Shutdown",              /* PCIE_FW_EVAL_DEVICESHUTDOWN */
+               "Reserved",                     /* reserved */
+       };
+       u32 pcie_fw;
+
+       pcie_fw = t4_read_reg(adap, MA_PCIE_FW);
+       if (pcie_fw & FW_PCIE_FW_ERR)
+               dev_err(adap->pdev_dev, "Firmware reports adapter error: %s\n",
+                       reason[FW_PCIE_FW_EVAL_GET(pcie_fw)]);
+}
+
 /*
  * Get the reply to a mailbox command and store it in @rpl in big-endian order.
  */
@@ -300,6 +328,7 @@ int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size,
        dump_mbox(adap, mbox, data_reg);
        dev_err(adap->pdev_dev, "command %#x in mailbox %d timed out\n",
                *(const u8 *)cmd, mbox);
+       t4_report_fw_error(adap);
        return -ETIMEDOUT;
 }
 
@@ -566,6 +595,7 @@ int t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr,
 #define VPD_BASE           0x400
 #define VPD_BASE_OLD       0
 #define VPD_LEN            1024
+#define CHELSIO_VPD_UNIQUE_ID 0x82
 
 /**
  *     t4_seeprom_wp - enable/disable EEPROM write protection
@@ -603,7 +633,14 @@ int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
        ret = pci_read_vpd(adapter->pdev, VPD_BASE, sizeof(u32), vpd);
        if (ret < 0)
                goto out;
-       addr = *vpd == 0x82 ? VPD_BASE : VPD_BASE_OLD;
+
+       /* The VPD shall have a unique identifier specified by the PCI SIG.
+        * For chelsio adapters, the identifier is 0x82. The first byte of a VPD
+        * shall be CHELSIO_VPD_UNIQUE_ID (0x82). The VPD programming software
+        * is expected to automatically put this entry at the
+        * beginning of the VPD.
+        */
+       addr = *vpd == CHELSIO_VPD_UNIQUE_ID ? VPD_BASE : VPD_BASE_OLD;
 
        ret = pci_read_vpd(adapter->pdev, addr, VPD_LEN, vpd);
        if (ret < 0)
@@ -667,6 +704,7 @@ 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);
+       i = pci_vpd_info_field_size(vpd + pn - PCI_VPD_INFO_FLD_HDR_SIZE);
        memcpy(p->pn, vpd + pn, min(i, PN_LEN));
        strim(p->pn);
 
@@ -1394,15 +1432,18 @@ static void pcie_intr_handler(struct adapter *adapter)
 
        int fat;
 
-       fat = t4_handle_intr_status(adapter,
-                                   PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS,
-                                   sysbus_intr_info) +
-             t4_handle_intr_status(adapter,
-                                   PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS,
-                                   pcie_port_intr_info) +
-             t4_handle_intr_status(adapter, PCIE_INT_CAUSE,
-                                   is_t4(adapter->params.chip) ?
-                                   pcie_intr_info : t5_pcie_intr_info);
+       if (is_t4(adapter->params.chip))
+               fat = t4_handle_intr_status(adapter,
+                                           PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS,
+                                           sysbus_intr_info) +
+                       t4_handle_intr_status(adapter,
+                                             PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS,
+                                             pcie_port_intr_info) +
+                       t4_handle_intr_status(adapter, PCIE_INT_CAUSE,
+                                             pcie_intr_info);
+       else
+               fat = t4_handle_intr_status(adapter, PCIE_INT_CAUSE,
+                                           t5_pcie_intr_info);
 
        if (fat)
                t4_fatal_err(adapter);
@@ -1521,6 +1562,9 @@ static void cim_intr_handler(struct adapter *adapter)
 
        int fat;
 
+       if (t4_read_reg(adapter, MA_PCIE_FW) & FW_PCIE_FW_ERR)
+               t4_report_fw_error(adapter);
+
        fat = t4_handle_intr_status(adapter, CIM_HOST_INT_CAUSE,
                                    cim_intr_info) +
              t4_handle_intr_status(adapter, CIM_HOST_UPACC_INT_CAUSE,
@@ -1768,10 +1812,16 @@ static void ma_intr_handler(struct adapter *adap)
 {
        u32 v, status = t4_read_reg(adap, MA_INT_CAUSE);
 
-       if (status & MEM_PERR_INT_CAUSE)
+       if (status & MEM_PERR_INT_CAUSE) {
                dev_alert(adap->pdev_dev,
                          "MA parity error, parity status %#x\n",
                          t4_read_reg(adap, MA_PARITY_ERROR_STATUS));
+               if (is_t5(adap->params.chip))
+                       dev_alert(adap->pdev_dev,
+                                 "MA parity error, parity status %#x\n",
+                                 t4_read_reg(adap,
+                                             MA_PARITY_ERROR_STATUS2));
+       }
        if (status & MEM_WRAP_INT_CAUSE) {
                v = t4_read_reg(adap, MA_INT_WRAP_STATUS);
                dev_alert(adap->pdev_dev, "MA address wrap-around error by "
@@ -2733,12 +2783,16 @@ retry:
        /*
         * Issue the HELLO command to the firmware.  If it's not successful
         * but indicates that we got a "busy" or "timeout" condition, retry
-        * the HELLO until we exhaust our retry limit.
+        * the HELLO until we exhaust our retry limit.  If we do exceed our
+        * retry limit, check to see if the firmware left us any error
+        * information and report that if so.
         */
        ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
        if (ret < 0) {
                if ((ret == -EBUSY || ret == -ETIMEDOUT) && retries-- > 0)
                        goto retry;
+               if (t4_read_reg(adap, MA_PCIE_FW) & FW_PCIE_FW_ERR)
+                       t4_report_fw_error(adap);
                return ret;
        }
 
@@ -3742,6 +3796,7 @@ int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl)
                        lc->link_ok = link_ok;
                        lc->speed = speed;
                        lc->fc = fc;
+                       lc->supported = be16_to_cpu(p->u.info.pcap);
                        t4_os_link_changed(adap, port, link_ok);
                }
                if (mod != pi->mod_type) {
index e3146e83df2043ae59436e7eff6b8c276a3fb3e4..39fb325474f7e7499534d142d47cdcd0b7fbc1f4 100644 (file)
 #define  MEM_WRAP_CLIENT_NUM_GET(x) (((x) & MEM_WRAP_CLIENT_NUM_MASK) >> MEM_WRAP_CLIENT_NUM_SHIFT)
 #define MA_PCIE_FW 0x30b8
 #define MA_PARITY_ERROR_STATUS 0x77f4
+#define MA_PARITY_ERROR_STATUS2 0x7804
 
 #define MA_EXT_MEMORY1_BAR 0x7808
 #define EDC_0_BASE_ADDR 0x7900
 #define  TRCMULTIFILTER     0x00000001U
 
 #define MPS_TRC_RSS_CONTROL 0x9808
+#define MPS_T5_TRC_RSS_CONTROL 0xa00c
 #define  RSSCONTROL_MASK    0x00ff0000U
 #define  RSSCONTROL_SHIFT   16
 #define  RSSCONTROL(x)      ((x) << RSSCONTROL_SHIFT)
index 0549170d7e2ed2b60f68322b4ef44887471bbc52..3409756a85b95586f7640033dc06bb274c4db139 100644 (file)
@@ -1227,6 +1227,7 @@ struct fw_eq_eth_cmd {
 #define FW_EQ_ETH_CMD_CIDXFTHRESH(x) ((x) << 16)
 #define FW_EQ_ETH_CMD_EQSIZE(x) ((x) << 0)
 
+#define FW_EQ_ETH_CMD_AUTOEQUEQE (1U << 30)
 #define FW_EQ_ETH_CMD_VIID(x) ((x) << 16)
 
 struct fw_eq_ctrl_cmd {
@@ -2227,6 +2228,10 @@ struct fw_debug_cmd {
 #define FW_PCIE_FW_MASTER(x)     ((x) << FW_PCIE_FW_MASTER_SHIFT)
 #define FW_PCIE_FW_MASTER_GET(x) (((x) >> FW_PCIE_FW_MASTER_SHIFT) & \
                                 FW_PCIE_FW_MASTER_MASK)
+#define FW_PCIE_FW_EVAL_MASK   0x7
+#define FW_PCIE_FW_EVAL_SHIFT  24
+#define FW_PCIE_FW_EVAL_GET(x) (((x) >> FW_PCIE_FW_EVAL_SHIFT) & \
+                                FW_PCIE_FW_EVAL_MASK)
 
 struct fw_hdr {
        u8 ver;
index bdfa80ca5e317cee72c925a4112bdeaaf2551799..a5fb9493dee826563561072185d85ccc46513337 100644 (file)
@@ -2250,7 +2250,8 @@ int t4vf_sge_alloc_eth_txq(struct adapter *adapter, struct sge_eth_txq *txq,
        cmd.alloc_to_len16 = cpu_to_be32(FW_EQ_ETH_CMD_ALLOC |
                                         FW_EQ_ETH_CMD_EQSTART |
                                         FW_LEN16(cmd));
-       cmd.viid_pkd = cpu_to_be32(FW_EQ_ETH_CMD_VIID(pi->viid));
+       cmd.viid_pkd = cpu_to_be32(FW_EQ_ETH_CMD_AUTOEQUEQE |
+                                  FW_EQ_ETH_CMD_VIID(pi->viid));
        cmd.fetchszm_to_iqid =
                cpu_to_be32(FW_EQ_ETH_CMD_HOSTFCMODE(SGE_HOSTFCMODE_STPG) |
                            FW_EQ_ETH_CMD_PCIECHN(pi->port_id) |
index 962510f391dfcb3b8e041dd5ad89391b093c7bb4..5ba5ad071bb619dee3c5842fc23b7ff3c3e19216 100644 (file)
@@ -186,6 +186,7 @@ struct enic {
        ____cacheline_aligned struct vnic_cq cq[ENIC_CQ_MAX];
        unsigned int cq_count;
        struct enic_rfs_flw_tbl rfs_h;
+       u32 rx_copybreak;
 };
 
 static inline struct device *enic_get_dev(struct enic *enic)
index 523c9ceb04c020265b8ceabf3fbf209d9db34af6..85173d6207584aadc2546f880c22446fee0f09ff 100644 (file)
@@ -379,6 +379,43 @@ static int enic_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
        return ret;
 }
 
+static int enic_get_tunable(struct net_device *dev,
+                           const struct ethtool_tunable *tuna, void *data)
+{
+       struct enic *enic = netdev_priv(dev);
+       int ret = 0;
+
+       switch (tuna->id) {
+       case ETHTOOL_RX_COPYBREAK:
+               *(u32 *)data = enic->rx_copybreak;
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+static int enic_set_tunable(struct net_device *dev,
+                           const struct ethtool_tunable *tuna,
+                           const void *data)
+{
+       struct enic *enic = netdev_priv(dev);
+       int ret = 0;
+
+       switch (tuna->id) {
+       case ETHTOOL_RX_COPYBREAK:
+               enic->rx_copybreak = *(u32 *)data;
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
 static const struct ethtool_ops enic_ethtool_ops = {
        .get_settings = enic_get_settings,
        .get_drvinfo = enic_get_drvinfo,
@@ -391,6 +428,8 @@ static const struct ethtool_ops enic_ethtool_ops = {
        .get_coalesce = enic_get_coalesce,
        .set_coalesce = enic_set_coalesce,
        .get_rxnfc = enic_get_rxnfc,
+       .get_tunable = enic_get_tunable,
+       .set_tunable = enic_set_tunable,
 };
 
 void enic_set_ethtool_ops(struct net_device *netdev)
index c8832bc1c5f776a9199acbca27b693941c83d1fe..929bfe70080ac040bd879ede472d72744aaa300c 100644 (file)
@@ -66,6 +66,8 @@
 #define PCI_DEVICE_ID_CISCO_VIC_ENET_DYN     0x0044  /* enet dynamic vnic */
 #define PCI_DEVICE_ID_CISCO_VIC_ENET_VF      0x0071  /* enet SRIOV VF */
 
+#define RX_COPYBREAK_DEFAULT           256
+
 /* Supported devices */
 static const struct pci_device_id enic_id_table[] = {
        { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET) },
@@ -924,6 +926,7 @@ static void enic_free_rq_buf(struct vnic_rq *rq, struct vnic_rq_buf *buf)
        pci_unmap_single(enic->pdev, buf->dma_addr,
                buf->len, PCI_DMA_FROMDEVICE);
        dev_kfree_skb_any(buf->os_buf);
+       buf->os_buf = NULL;
 }
 
 static int enic_rq_alloc_buf(struct vnic_rq *rq)
@@ -934,7 +937,24 @@ static int enic_rq_alloc_buf(struct vnic_rq *rq)
        unsigned int len = netdev->mtu + VLAN_ETH_HLEN;
        unsigned int os_buf_index = 0;
        dma_addr_t dma_addr;
+       struct vnic_rq_buf *buf = rq->to_use;
+
+       if (buf->os_buf) {
+               buf = buf->next;
+               rq->to_use = buf;
+               rq->ring.desc_avail--;
+               if ((buf->index & VNIC_RQ_RETURN_RATE) == 0) {
+                       /* Adding write memory barrier prevents compiler and/or
+                        * CPU reordering, thus avoiding descriptor posting
+                        * before descriptor is initialized. Otherwise, hardware
+                        * can read stale descriptor fields.
+                        */
+                       wmb();
+                       iowrite32(buf->index, &rq->ctrl->posted_index);
+               }
 
+               return 0;
+       }
        skb = netdev_alloc_skb_ip_align(netdev, len);
        if (!skb)
                return -ENOMEM;
@@ -957,6 +977,25 @@ static void enic_intr_update_pkt_size(struct vnic_rx_bytes_counter *pkt_size,
                pkt_size->small_pkt_bytes_cnt += pkt_len;
 }
 
+static bool enic_rxcopybreak(struct net_device *netdev, struct sk_buff **skb,
+                            struct vnic_rq_buf *buf, u16 len)
+{
+       struct enic *enic = netdev_priv(netdev);
+       struct sk_buff *new_skb;
+
+       if (len > enic->rx_copybreak)
+               return false;
+       new_skb = netdev_alloc_skb_ip_align(netdev, len);
+       if (!new_skb)
+               return false;
+       pci_dma_sync_single_for_cpu(enic->pdev, buf->dma_addr, len,
+                                   DMA_FROM_DEVICE);
+       memcpy(new_skb->data, (*skb)->data, len);
+       *skb = new_skb;
+
+       return true;
+}
+
 static void enic_rq_indicate_buf(struct vnic_rq *rq,
        struct cq_desc *cq_desc, struct vnic_rq_buf *buf,
        int skipped, void *opaque)
@@ -978,9 +1017,6 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq,
                return;
 
        skb = buf->os_buf;
-       prefetch(skb->data - NET_IP_ALIGN);
-       pci_unmap_single(enic->pdev, buf->dma_addr,
-               buf->len, PCI_DMA_FROMDEVICE);
 
        cq_enet_rq_desc_dec((struct cq_enet_rq_desc *)cq_desc,
                &type, &color, &q_number, &completed_index,
@@ -1011,6 +1047,13 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq,
                /* Good receive
                 */
 
+               if (!enic_rxcopybreak(netdev, &skb, buf, bytes_written)) {
+                       buf->os_buf = NULL;
+                       pci_unmap_single(enic->pdev, buf->dma_addr, buf->len,
+                                        PCI_DMA_FROMDEVICE);
+               }
+               prefetch(skb->data - NET_IP_ALIGN);
+
                skb_put(skb, bytes_written);
                skb->protocol = eth_type_trans(skb, netdev);
                skb_record_rx_queue(skb, q_number);
@@ -2531,6 +2574,7 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                dev_err(dev, "Cannot register net device, aborting\n");
                goto err_out_dev_deinit;
        }
+       enic->rx_copybreak = RX_COPYBREAK_DEFAULT;
 
        return 0;
 
index 37472ce4fac310a933a1f332a5df451a1cdbcc5d..62f7b7baf93cd79f77de9aceb8d977461c075cb7 100644 (file)
@@ -847,8 +847,7 @@ int vnic_dev_intr_coal_timer_info(struct vnic_dev *vdev)
         */
        if ((err == ERR_ECMDUNKNOWN) ||
                (!err && !(vdev->args[0] && vdev->args[1] && vdev->args[2]))) {
-               pr_warning("Using default conversion factor for "
-                       "interrupt coalesce timer\n");
+               pr_warn("Using default conversion factor for interrupt coalesce timer\n");
                vnic_dev_intr_coal_timer_info_default(vdev);
                return 0;
        }
index 322213d901d5ec663ef3831f81786b199cdd41bd..c8205606c7757ff3345acef81d57a5c0118497e3 100644 (file)
@@ -328,10 +328,10 @@ static void allocate_rx_buffer(struct net_device *);
 static void update_cr6(u32, void __iomem *);
 static void send_filter_frame(struct DEVICE *);
 static void dm9132_id_table(struct DEVICE *);
-static u16 phy_read(void __iomem *, u8, u8, u32);
-static void phy_write(void __iomem *, u8, u8, u16, u32);
-static void phy_write_1bit(void __iomem *, u32);
-static u16 phy_read_1bit(void __iomem *);
+static u16 dmfe_phy_read(void __iomem *, u8, u8, u32);
+static void dmfe_phy_write(void __iomem *, u8, u8, u16, u32);
+static void dmfe_phy_write_1bit(void __iomem *, u32);
+static u16 dmfe_phy_read_1bit(void __iomem *);
 static u8 dmfe_sense_speed(struct dmfe_board_info *);
 static void dmfe_process_mode(struct dmfe_board_info *);
 static void dmfe_timer(unsigned long);
@@ -770,7 +770,7 @@ static int dmfe_stop(struct DEVICE *dev)
        /* Reset & stop DM910X board */
        dw32(DCR0, DM910X_RESET);
        udelay(100);
-       phy_write(ioaddr, db->phy_addr, 0, 0x8000, db->chip_id);
+       dmfe_phy_write(ioaddr, db->phy_addr, 0, 0x8000, db->chip_id);
 
        /* free interrupt */
        free_irq(db->pdev->irq, dev);
@@ -1154,7 +1154,7 @@ static void dmfe_timer(unsigned long data)
                if (db->chip_type && (db->chip_id==PCI_DM9102_ID)) {
                        db->cr6_data &= ~0x40000;
                        update_cr6(db->cr6_data, ioaddr);
-                       phy_write(ioaddr, db->phy_addr, 0, 0x1000, db->chip_id);
+                       dmfe_phy_write(ioaddr, db->phy_addr, 0, 0x1000, db->chip_id);
                        db->cr6_data |= 0x40000;
                        update_cr6(db->cr6_data, ioaddr);
                        db->timer.expires = DMFE_TIMER_WUT + HZ * 2;
@@ -1230,9 +1230,9 @@ static void dmfe_timer(unsigned long data)
        */
 
        /* need a dummy read because of PHY's register latch*/
-       phy_read (db->ioaddr, db->phy_addr, 1, db->chip_id);
-       link_ok_phy = (phy_read (db->ioaddr,
-                      db->phy_addr, 1, db->chip_id) & 0x4) ? 1 : 0;
+       dmfe_phy_read (db->ioaddr, db->phy_addr, 1, db->chip_id);
+       link_ok_phy = (dmfe_phy_read (db->ioaddr,
+                                     db->phy_addr, 1, db->chip_id) & 0x4) ? 1 : 0;
 
        if (link_ok_phy != link_ok) {
                DMFE_DBUG (0, "PHY and chip report different link status", 0);
@@ -1247,8 +1247,8 @@ static void dmfe_timer(unsigned long data)
                /* For Force 10/100M Half/Full mode: Enable Auto-Nego mode */
                /* AUTO or force 1M Homerun/Longrun don't need */
                if ( !(db->media_mode & 0x38) )
-                       phy_write(db->ioaddr, db->phy_addr,
-                                 0, 0x1000, db->chip_id);
+                       dmfe_phy_write(db->ioaddr, db->phy_addr,
+                                      0, 0x1000, db->chip_id);
 
                /* AUTO mode, if INT phyxcer link failed, select EXT device */
                if (db->media_mode & DMFE_AUTO) {
@@ -1649,16 +1649,16 @@ static u8 dmfe_sense_speed(struct dmfe_board_info *db)
        /* CR6 bit18=0, select 10/100M */
        update_cr6(db->cr6_data & ~0x40000, ioaddr);
 
-       phy_mode = phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id);
-       phy_mode = phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id);
+       phy_mode = dmfe_phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id);
+       phy_mode = dmfe_phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id);
 
        if ( (phy_mode & 0x24) == 0x24 ) {
                if (db->chip_id == PCI_DM9132_ID)       /* DM9132 */
-                       phy_mode = phy_read(db->ioaddr,
-                                   db->phy_addr, 7, db->chip_id) & 0xf000;
+                       phy_mode = dmfe_phy_read(db->ioaddr,
+                                                db->phy_addr, 7, db->chip_id) & 0xf000;
                else                            /* DM9102/DM9102A */
-                       phy_mode = phy_read(db->ioaddr,
-                                   db->phy_addr, 17, db->chip_id) & 0xf000;
+                       phy_mode = dmfe_phy_read(db->ioaddr,
+                                                db->phy_addr, 17, db->chip_id) & 0xf000;
                switch (phy_mode) {
                case 0x1000: db->op_mode = DMFE_10MHF; break;
                case 0x2000: db->op_mode = DMFE_10MFD; break;
@@ -1695,15 +1695,15 @@ static void dmfe_set_phyxcer(struct dmfe_board_info *db)
 
        /* DM9009 Chip: Phyxcer reg18 bit12=0 */
        if (db->chip_id == PCI_DM9009_ID) {
-               phy_reg = phy_read(db->ioaddr,
-                                  db->phy_addr, 18, db->chip_id) & ~0x1000;
+               phy_reg = dmfe_phy_read(db->ioaddr,
+                                       db->phy_addr, 18, db->chip_id) & ~0x1000;
 
-               phy_write(db->ioaddr,
-                         db->phy_addr, 18, phy_reg, db->chip_id);
+               dmfe_phy_write(db->ioaddr,
+                              db->phy_addr, 18, phy_reg, db->chip_id);
        }
 
        /* Phyxcer capability setting */
-       phy_reg = phy_read(db->ioaddr, db->phy_addr, 4, db->chip_id) & ~0x01e0;
+       phy_reg = dmfe_phy_read(db->ioaddr, db->phy_addr, 4, db->chip_id) & ~0x01e0;
 
        if (db->media_mode & DMFE_AUTO) {
                /* AUTO Mode */
@@ -1724,13 +1724,13 @@ static void dmfe_set_phyxcer(struct dmfe_board_info *db)
                phy_reg|=db->PHY_reg4;
                db->media_mode|=DMFE_AUTO;
        }
-       phy_write(db->ioaddr, db->phy_addr, 4, phy_reg, db->chip_id);
+       dmfe_phy_write(db->ioaddr, db->phy_addr, 4, phy_reg, db->chip_id);
 
        /* Restart Auto-Negotiation */
        if ( db->chip_type && (db->chip_id == PCI_DM9102_ID) )
-               phy_write(db->ioaddr, db->phy_addr, 0, 0x1800, db->chip_id);
+               dmfe_phy_write(db->ioaddr, db->phy_addr, 0, 0x1800, db->chip_id);
        if ( !db->chip_type )
-               phy_write(db->ioaddr, db->phy_addr, 0, 0x1200, db->chip_id);
+               dmfe_phy_write(db->ioaddr, db->phy_addr, 0, 0x1200, db->chip_id);
 }
 
 
@@ -1762,7 +1762,7 @@ static void dmfe_process_mode(struct dmfe_board_info *db)
        /* 10/100M phyxcer force mode need */
        if ( !(db->media_mode & 0x18)) {
                /* Forece Mode */
-               phy_reg = phy_read(db->ioaddr, db->phy_addr, 6, db->chip_id);
+               phy_reg = dmfe_phy_read(db->ioaddr, db->phy_addr, 6, db->chip_id);
                if ( !(phy_reg & 0x1) ) {
                        /* parter without N-Way capability */
                        phy_reg = 0x0;
@@ -1772,12 +1772,12 @@ static void dmfe_process_mode(struct dmfe_board_info *db)
                        case DMFE_100MHF: phy_reg = 0x2000; break;
                        case DMFE_100MFD: phy_reg = 0x2100; break;
                        }
-                       phy_write(db->ioaddr,
-                                 db->phy_addr, 0, phy_reg, db->chip_id);
+                       dmfe_phy_write(db->ioaddr,
+                                      db->phy_addr, 0, phy_reg, db->chip_id);
                                if ( db->chip_type && (db->chip_id == PCI_DM9102_ID) )
                                mdelay(20);
-                       phy_write(db->ioaddr,
-                                 db->phy_addr, 0, phy_reg, db->chip_id);
+                       dmfe_phy_write(db->ioaddr,
+                                      db->phy_addr, 0, phy_reg, db->chip_id);
                }
        }
 }
@@ -1787,8 +1787,8 @@ static void dmfe_process_mode(struct dmfe_board_info *db)
  *     Write a word to Phy register
  */
 
-static void phy_write(void __iomem *ioaddr, u8 phy_addr, u8 offset,
-                     u16 phy_data, u32 chip_id)
+static void dmfe_phy_write(void __iomem *ioaddr, u8 phy_addr, u8 offset,
+                          u16 phy_data, u32 chip_id)
 {
        u16 i;
 
@@ -1799,34 +1799,34 @@ static void phy_write(void __iomem *ioaddr, u8 phy_addr, u8 offset,
 
                /* Send 33 synchronization clock to Phy controller */
                for (i = 0; i < 35; i++)
-                       phy_write_1bit(ioaddr, PHY_DATA_1);
+                       dmfe_phy_write_1bit(ioaddr, PHY_DATA_1);
 
                /* Send start command(01) to Phy */
-               phy_write_1bit(ioaddr, PHY_DATA_0);
-               phy_write_1bit(ioaddr, PHY_DATA_1);
+               dmfe_phy_write_1bit(ioaddr, PHY_DATA_0);
+               dmfe_phy_write_1bit(ioaddr, PHY_DATA_1);
 
                /* Send write command(01) to Phy */
-               phy_write_1bit(ioaddr, PHY_DATA_0);
-               phy_write_1bit(ioaddr, PHY_DATA_1);
+               dmfe_phy_write_1bit(ioaddr, PHY_DATA_0);
+               dmfe_phy_write_1bit(ioaddr, PHY_DATA_1);
 
                /* Send Phy address */
                for (i = 0x10; i > 0; i = i >> 1)
-                       phy_write_1bit(ioaddr,
-                                      phy_addr & i ? PHY_DATA_1 : PHY_DATA_0);
+                       dmfe_phy_write_1bit(ioaddr,
+                                           phy_addr & i ? PHY_DATA_1 : PHY_DATA_0);
 
                /* Send register address */
                for (i = 0x10; i > 0; i = i >> 1)
-                       phy_write_1bit(ioaddr,
-                                      offset & i ? PHY_DATA_1 : PHY_DATA_0);
+                       dmfe_phy_write_1bit(ioaddr,
+                                           offset & i ? PHY_DATA_1 : PHY_DATA_0);
 
                /* written trasnition */
-               phy_write_1bit(ioaddr, PHY_DATA_1);
-               phy_write_1bit(ioaddr, PHY_DATA_0);
+               dmfe_phy_write_1bit(ioaddr, PHY_DATA_1);
+               dmfe_phy_write_1bit(ioaddr, PHY_DATA_0);
 
                /* Write a word data to PHY controller */
                for ( i = 0x8000; i > 0; i >>= 1)
-                       phy_write_1bit(ioaddr,
-                                      phy_data & i ? PHY_DATA_1 : PHY_DATA_0);
+                       dmfe_phy_write_1bit(ioaddr,
+                                           phy_data & i ? PHY_DATA_1 : PHY_DATA_0);
        }
 }
 
@@ -1835,7 +1835,7 @@ static void phy_write(void __iomem *ioaddr, u8 phy_addr, u8 offset,
  *     Read a word data from phy register
  */
 
-static u16 phy_read(void __iomem *ioaddr, u8 phy_addr, u8 offset, u32 chip_id)
+static u16 dmfe_phy_read(void __iomem *ioaddr, u8 phy_addr, u8 offset, u32 chip_id)
 {
        int i;
        u16 phy_data;
@@ -1848,33 +1848,33 @@ static u16 phy_read(void __iomem *ioaddr, u8 phy_addr, u8 offset, u32 chip_id)
 
                /* Send 33 synchronization clock to Phy controller */
                for (i = 0; i < 35; i++)
-                       phy_write_1bit(ioaddr, PHY_DATA_1);
+                       dmfe_phy_write_1bit(ioaddr, PHY_DATA_1);
 
                /* Send start command(01) to Phy */
-               phy_write_1bit(ioaddr, PHY_DATA_0);
-               phy_write_1bit(ioaddr, PHY_DATA_1);
+               dmfe_phy_write_1bit(ioaddr, PHY_DATA_0);
+               dmfe_phy_write_1bit(ioaddr, PHY_DATA_1);
 
                /* Send read command(10) to Phy */
-               phy_write_1bit(ioaddr, PHY_DATA_1);
-               phy_write_1bit(ioaddr, PHY_DATA_0);
+               dmfe_phy_write_1bit(ioaddr, PHY_DATA_1);
+               dmfe_phy_write_1bit(ioaddr, PHY_DATA_0);
 
                /* Send Phy address */
                for (i = 0x10; i > 0; i = i >> 1)
-                       phy_write_1bit(ioaddr,
-                                      phy_addr & i ? PHY_DATA_1 : PHY_DATA_0);
+                       dmfe_phy_write_1bit(ioaddr,
+                                           phy_addr & i ? PHY_DATA_1 : PHY_DATA_0);
 
                /* Send register address */
                for (i = 0x10; i > 0; i = i >> 1)
-                       phy_write_1bit(ioaddr,
-                                      offset & i ? PHY_DATA_1 : PHY_DATA_0);
+                       dmfe_phy_write_1bit(ioaddr,
+                                           offset & i ? PHY_DATA_1 : PHY_DATA_0);
 
                /* Skip transition state */
-               phy_read_1bit(ioaddr);
+               dmfe_phy_read_1bit(ioaddr);
 
                /* read 16bit data */
                for (phy_data = 0, i = 0; i < 16; i++) {
                        phy_data <<= 1;
-                       phy_data |= phy_read_1bit(ioaddr);
+                       phy_data |= dmfe_phy_read_1bit(ioaddr);
                }
        }
 
@@ -1886,7 +1886,7 @@ static u16 phy_read(void __iomem *ioaddr, u8 phy_addr, u8 offset, u32 chip_id)
  *     Write one bit data to Phy Controller
  */
 
-static void phy_write_1bit(void __iomem *ioaddr, u32 phy_data)
+static void dmfe_phy_write_1bit(void __iomem *ioaddr, u32 phy_data)
 {
        dw32(DCR9, phy_data);           /* MII Clock Low */
        udelay(1);
@@ -1901,7 +1901,7 @@ static void phy_write_1bit(void __iomem *ioaddr, u32 phy_data)
  *     Read one bit phy data from PHY controller
  */
 
-static u16 phy_read_1bit(void __iomem *ioaddr)
+static u16 dmfe_phy_read_1bit(void __iomem *ioaddr)
 {
        u16 phy_data;
 
@@ -1995,11 +1995,11 @@ static void dmfe_parse_srom(struct dmfe_board_info * db)
        /* Check DM9801 or DM9802 present or not */
        db->HPNA_present = 0;
        update_cr6(db->cr6_data | 0x40000, db->ioaddr);
-       tmp_reg = phy_read(db->ioaddr, db->phy_addr, 3, db->chip_id);
+       tmp_reg = dmfe_phy_read(db->ioaddr, db->phy_addr, 3, db->chip_id);
        if ( ( tmp_reg & 0xfff0 ) == 0xb900 ) {
                /* DM9801 or DM9802 present */
                db->HPNA_timer = 8;
-               if ( phy_read(db->ioaddr, db->phy_addr, 31, db->chip_id) == 0x4404) {
+               if ( dmfe_phy_read(db->ioaddr, db->phy_addr, 31, db->chip_id) == 0x4404) {
                        /* DM9801 HomeRun */
                        db->HPNA_present = 1;
                        dmfe_program_DM9801(db, tmp_reg);
@@ -2025,29 +2025,29 @@ static void dmfe_program_DM9801(struct dmfe_board_info * db, int HPNA_rev)
        switch(HPNA_rev) {
        case 0xb900: /* DM9801 E3 */
                db->HPNA_command |= 0x1000;
-               reg25 = phy_read(db->ioaddr, db->phy_addr, 24, db->chip_id);
+               reg25 = dmfe_phy_read(db->ioaddr, db->phy_addr, 24, db->chip_id);
                reg25 = ( (reg25 + HPNA_NoiseFloor) & 0xff) | 0xf000;
-               reg17 = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id);
+               reg17 = dmfe_phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id);
                break;
        case 0xb901: /* DM9801 E4 */
-               reg25 = phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id);
+               reg25 = dmfe_phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id);
                reg25 = (reg25 & 0xff00) + HPNA_NoiseFloor;
-               reg17 = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id);
+               reg17 = dmfe_phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id);
                reg17 = (reg17 & 0xfff0) + HPNA_NoiseFloor + 3;
                break;
        case 0xb902: /* DM9801 E5 */
        case 0xb903: /* DM9801 E6 */
        default:
                db->HPNA_command |= 0x1000;
-               reg25 = phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id);
+               reg25 = dmfe_phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id);
                reg25 = (reg25 & 0xff00) + HPNA_NoiseFloor - 5;
-               reg17 = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id);
+               reg17 = dmfe_phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id);
                reg17 = (reg17 & 0xfff0) + HPNA_NoiseFloor;
                break;
        }
-       phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command, db->chip_id);
-       phy_write(db->ioaddr, db->phy_addr, 17, reg17, db->chip_id);
-       phy_write(db->ioaddr, db->phy_addr, 25, reg25, db->chip_id);
+       dmfe_phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command, db->chip_id);
+       dmfe_phy_write(db->ioaddr, db->phy_addr, 17, reg17, db->chip_id);
+       dmfe_phy_write(db->ioaddr, db->phy_addr, 25, reg25, db->chip_id);
 }
 
 
@@ -2060,10 +2060,10 @@ static void dmfe_program_DM9802(struct dmfe_board_info * db)
        uint phy_reg;
 
        if ( !HPNA_NoiseFloor ) HPNA_NoiseFloor = DM9802_NOISE_FLOOR;
-       phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command, db->chip_id);
-       phy_reg = phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id);
+       dmfe_phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command, db->chip_id);
+       phy_reg = dmfe_phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id);
        phy_reg = ( phy_reg & 0xff00) + HPNA_NoiseFloor;
-       phy_write(db->ioaddr, db->phy_addr, 25, phy_reg, db->chip_id);
+       dmfe_phy_write(db->ioaddr, db->phy_addr, 25, phy_reg, db->chip_id);
 }
 
 
@@ -2077,7 +2077,7 @@ static void dmfe_HPNA_remote_cmd_chk(struct dmfe_board_info * db)
        uint phy_reg;
 
        /* Got remote device status */
-       phy_reg = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id) & 0x60;
+       phy_reg = dmfe_phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id) & 0x60;
        switch(phy_reg) {
        case 0x00: phy_reg = 0x0a00;break; /* LP/LS */
        case 0x20: phy_reg = 0x0900;break; /* LP/HS */
@@ -2087,8 +2087,8 @@ static void dmfe_HPNA_remote_cmd_chk(struct dmfe_board_info * db)
 
        /* Check remote device status match our setting ot not */
        if ( phy_reg != (db->HPNA_command & 0x0f00) ) {
-               phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command,
-                         db->chip_id);
+               dmfe_phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command,
+                              db->chip_id);
                db->HPNA_timer=8;
        } else
                db->HPNA_timer=600;     /* Match, every 10 minutes, check */
index 056b44b934773cb0084d5126dd7946d08bb24c46..d1017509b08ac1e171a12a89770373a5057c5d64 100644 (file)
@@ -1,5 +1,5 @@
  /*
- * drivers/net/ethernet/beckhoff/ec_bhf.c
+ * drivers/net/ethernet/ec_bhf.c
  *
  * Copyright (C) 2014 Darek Marcinkiewicz <reksio@newterm.pl>
  *
@@ -18,9 +18,6 @@
  * Those can be found on Bechhoff CX50xx industrial PCs.
  */
 
-#if 0
-#define DEBUG
-#endif
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -74,6 +71,8 @@
 
 #define DMA_WINDOW_SIZE_MASK   0xfffffffc
 
+#define ETHERCAT_MASTER_ID     0x14
+
 static struct pci_device_id ids[] = {
        { PCI_DEVICE(0x15ec, 0x5000), },
        { 0, }
@@ -131,7 +130,6 @@ struct bhf_dma {
 
 struct ec_bhf_priv {
        struct net_device *net_dev;
-
        struct pci_dev *dev;
 
        void __iomem *io;
@@ -162,32 +160,6 @@ struct ec_bhf_priv {
 
 #define PRIV_TO_DEV(priv) (&(priv)->dev->dev)
 
-#define ETHERCAT_MASTER_ID     0x14
-
-static void ec_bhf_print_status(struct ec_bhf_priv *priv)
-{
-       struct device *dev = PRIV_TO_DEV(priv);
-
-       dev_dbg(dev, "Frame error counter: %d\n",
-               ioread8(priv->mac_io + MAC_FRAME_ERR_CNT));
-       dev_dbg(dev, "RX error counter: %d\n",
-               ioread8(priv->mac_io + MAC_RX_ERR_CNT));
-       dev_dbg(dev, "CRC error counter: %d\n",
-               ioread8(priv->mac_io + MAC_CRC_ERR_CNT));
-       dev_dbg(dev, "TX frame counter: %d\n",
-               ioread32(priv->mac_io + MAC_TX_FRAME_CNT));
-       dev_dbg(dev, "RX frame counter: %d\n",
-               ioread32(priv->mac_io + MAC_RX_FRAME_CNT));
-       dev_dbg(dev, "TX fifo level: %d\n",
-               ioread8(priv->mac_io + MAC_TX_FIFO_LVL));
-       dev_dbg(dev, "Dropped frames: %d\n",
-               ioread8(priv->mac_io + MAC_DROPPED_FRMS));
-       dev_dbg(dev, "Connected with CCAT slot: %d\n",
-               ioread8(priv->mac_io + MAC_CONNECTED_CCAT_FLAG));
-       dev_dbg(dev, "Link status: %d\n",
-               ioread8(priv->mii_io + MII_LINK_STATUS));
-}
-
 static void ec_bhf_reset(struct ec_bhf_priv *priv)
 {
        iowrite8(0, priv->mac_io + MAC_FRAME_ERR_CNT);
@@ -210,8 +182,6 @@ static void ec_bhf_send_packet(struct ec_bhf_priv *priv, struct tx_desc *desc)
        u32 addr = (u8 *)desc - priv->tx_buf.buf;
 
        iowrite32((ALIGN(len, 8) << 24) | addr, priv->fifo_io + FIFO_TX_REG);
-
-       dev_dbg(PRIV_TO_DEV(priv), "Done sending packet\n");
 }
 
 static int ec_bhf_desc_sent(struct tx_desc *desc)
@@ -244,7 +214,6 @@ static void ec_bhf_add_rx_desc(struct ec_bhf_priv *priv, struct rx_desc *desc)
 static void ec_bhf_process_rx(struct ec_bhf_priv *priv)
 {
        struct rx_desc *desc = &priv->rx_descs[priv->rx_dnext];
-       struct device *dev = PRIV_TO_DEV(priv);
 
        while (ec_bhf_pkt_received(desc)) {
                int pkt_size = (le16_to_cpu(desc->header.len) &
@@ -253,20 +222,16 @@ static void ec_bhf_process_rx(struct ec_bhf_priv *priv)
                struct sk_buff *skb;
 
                skb = netdev_alloc_skb_ip_align(priv->net_dev, pkt_size);
-               dev_dbg(dev, "Received packet, size: %d\n", pkt_size);
-
                if (skb) {
                        memcpy(skb_put(skb, pkt_size), data, pkt_size);
                        skb->protocol = eth_type_trans(skb, priv->net_dev);
-                       dev_dbg(dev, "Protocol type: %x\n", skb->protocol);
-
                        priv->stat_rx_bytes += pkt_size;
 
                        netif_rx(skb);
                } else {
-                       dev_err_ratelimited(dev,
-                               "Couldn't allocate a skb_buff for a packet of size %u\n",
-                               pkt_size);
+                       dev_err_ratelimited(PRIV_TO_DEV(priv),
+                                           "Couldn't allocate a skb_buff for a packet of size %u\n",
+                                           pkt_size);
                }
 
                desc->header.recv = 0;
@@ -276,7 +241,6 @@ static void ec_bhf_process_rx(struct ec_bhf_priv *priv)
                priv->rx_dnext = (priv->rx_dnext + 1) % priv->rx_dcount;
                desc = &priv->rx_descs[priv->rx_dnext];
        }
-
 }
 
 static enum hrtimer_restart ec_bhf_timer_fun(struct hrtimer *timer)
@@ -299,14 +263,7 @@ static int ec_bhf_setup_offsets(struct ec_bhf_priv *priv)
        unsigned block_count, i;
        void __iomem *ec_info;
 
-       dev_dbg(dev, "Info block:\n");
-       dev_dbg(dev, "Type of function: %x\n", (unsigned)ioread16(priv->io));
-       dev_dbg(dev, "Revision of function: %x\n",
-               (unsigned)ioread16(priv->io + INFO_BLOCK_REV));
-
        block_count = ioread8(priv->io + INFO_BLOCK_BLK_CNT);
-       dev_dbg(dev, "Number of function blocks: %x\n", block_count);
-
        for (i = 0; i < block_count; i++) {
                u16 type = ioread16(priv->io + i * INFO_BLOCK_SIZE +
                                    INFO_BLOCK_TYPE);
@@ -317,29 +274,17 @@ static int ec_bhf_setup_offsets(struct ec_bhf_priv *priv)
                dev_err(dev, "EtherCAT master with DMA block not found\n");
                return -ENODEV;
        }
-       dev_dbg(dev, "EtherCAT master with DMA block found at pos: %d\n", i);
 
        ec_info = priv->io + i * INFO_BLOCK_SIZE;
-       dev_dbg(dev, "EtherCAT master revision: %d\n",
-               ioread16(ec_info + INFO_BLOCK_REV));
 
        priv->tx_dma_chan = ioread8(ec_info + INFO_BLOCK_TX_CHAN);
-       dev_dbg(dev, "EtherCAT master tx dma channel: %d\n",
-               priv->tx_dma_chan);
-
        priv->rx_dma_chan = ioread8(ec_info + INFO_BLOCK_RX_CHAN);
-       dev_dbg(dev, "EtherCAT master rx dma channel: %d\n",
-                priv->rx_dma_chan);
 
        priv->ec_io = priv->io + ioread32(ec_info + INFO_BLOCK_OFFSET);
        priv->mii_io = priv->ec_io + ioread32(priv->ec_io + EC_MII_OFFSET);
        priv->fifo_io = priv->ec_io + ioread32(priv->ec_io + EC_FIFO_OFFSET);
        priv->mac_io = priv->ec_io + ioread32(priv->ec_io + EC_MAC_OFFSET);
 
-       dev_dbg(dev,
-               "EtherCAT block addres: %p, fifo address: %p, mii address: %p, mac address: %p\n",
-               priv->ec_io, priv->fifo_io, priv->mii_io, priv->mac_io);
-
        return 0;
 }
 
@@ -350,8 +295,6 @@ static netdev_tx_t ec_bhf_start_xmit(struct sk_buff *skb,
        struct tx_desc *desc;
        unsigned len;
 
-       dev_dbg(PRIV_TO_DEV(priv), "Starting xmit\n");
-
        desc = &priv->tx_descs[priv->tx_dnext];
 
        skb_copy_and_csum_dev(skb, desc->data);
@@ -366,15 +309,12 @@ static netdev_tx_t ec_bhf_start_xmit(struct sk_buff *skb,
        priv->tx_dnext = (priv->tx_dnext + 1) % priv->tx_dcount;
 
        if (!ec_bhf_desc_sent(&priv->tx_descs[priv->tx_dnext])) {
-               /* Make sure that update updates to tx_dnext are perceived
+               /* Make sure that updates to tx_dnext are perceived
                 * by timer routine.
                 */
                smp_wmb();
 
                netif_stop_queue(net_dev);
-
-               dev_dbg(PRIV_TO_DEV(priv), "Stopping netif queue\n");
-               ec_bhf_print_status(priv);
        }
 
        priv->stat_tx_bytes += len;
@@ -397,7 +337,6 @@ static int ec_bhf_alloc_dma_mem(struct ec_bhf_priv *priv,
 
        mask = ioread32(priv->dma_io + offset);
        mask &= DMA_WINDOW_SIZE_MASK;
-       dev_dbg(dev, "Read mask %x for channel %d\n", mask, channel);
 
        /* We want to allocate a chunk of memory that is:
         * - aligned to the mask we just read
@@ -408,12 +347,10 @@ static int ec_bhf_alloc_dma_mem(struct ec_bhf_priv *priv,
        buf->len = min_t(int, ~mask + 1, size);
        buf->alloc_len = 2 * buf->len;
 
-       dev_dbg(dev, "Allocating %d bytes for channel %d",
-               (int)buf->alloc_len, channel);
        buf->alloc = dma_alloc_coherent(dev, buf->alloc_len, &buf->alloc_phys,
                                        GFP_KERNEL);
        if (buf->alloc == NULL) {
-               dev_info(dev, "Failed to allocate buffer\n");
+               dev_err(dev, "Failed to allocate buffer\n");
                return -ENOMEM;
        }
 
@@ -422,8 +359,6 @@ static int ec_bhf_alloc_dma_mem(struct ec_bhf_priv *priv,
 
        iowrite32(0, priv->dma_io + offset + 4);
        iowrite32(buf->buf_phys, priv->dma_io + offset);
-       dev_dbg(dev, "Buffer: %x and read from dev: %x",
-               (unsigned)buf->buf_phys, ioread32(priv->dma_io + offset));
 
        return 0;
 }
@@ -433,7 +368,7 @@ static void ec_bhf_setup_tx_descs(struct ec_bhf_priv *priv)
        int i = 0;
 
        priv->tx_dcount = priv->tx_buf.len / sizeof(struct tx_desc);
-       priv->tx_descs = (struct tx_desc *) priv->tx_buf.buf;
+       priv->tx_descs = (struct tx_desc *)priv->tx_buf.buf;
        priv->tx_dnext = 0;
 
        for (i = 0; i < priv->tx_dcount; i++)
@@ -445,7 +380,7 @@ static void ec_bhf_setup_rx_descs(struct ec_bhf_priv *priv)
        int i;
 
        priv->rx_dcount = priv->rx_buf.len / sizeof(struct rx_desc);
-       priv->rx_descs = (struct rx_desc *) priv->rx_buf.buf;
+       priv->rx_descs = (struct rx_desc *)priv->rx_buf.buf;
        priv->rx_dnext = 0;
 
        for (i = 0; i < priv->rx_dcount; i++) {
@@ -469,8 +404,6 @@ static int ec_bhf_open(struct net_device *net_dev)
        struct device *dev = PRIV_TO_DEV(priv);
        int err = 0;
 
-       dev_info(dev, "Opening device\n");
-
        ec_bhf_reset(priv);
 
        err = ec_bhf_alloc_dma_mem(priv, &priv->rx_buf, priv->rx_dma_chan,
@@ -481,20 +414,13 @@ static int ec_bhf_open(struct net_device *net_dev)
        }
        ec_bhf_setup_rx_descs(priv);
 
-       dev_info(dev, "RX buffer allocated, address: %x\n",
-                (unsigned)priv->rx_buf.buf_phys);
-
        err = ec_bhf_alloc_dma_mem(priv, &priv->tx_buf, priv->tx_dma_chan,
                                   FIFO_SIZE * sizeof(struct tx_desc));
        if (err) {
                dev_err(dev, "Failed to allocate tx buffer\n");
                goto error_rx_free;
        }
-       dev_dbg(dev, "TX buffer allocated, addres: %x\n",
-               (unsigned)priv->tx_buf.buf_phys);
-
        iowrite8(0, priv->mii_io + MII_MAC_FILT_FLAG);
-
        ec_bhf_setup_tx_descs(priv);
 
        netif_start_queue(net_dev);
@@ -504,10 +430,6 @@ static int ec_bhf_open(struct net_device *net_dev)
        hrtimer_start(&priv->hrtimer, ktime_set(0, polling_frequency),
                      HRTIMER_MODE_REL);
 
-       dev_info(PRIV_TO_DEV(priv), "Device open\n");
-
-       ec_bhf_print_status(priv);
-
        return 0;
 
 error_rx_free:
@@ -640,9 +562,6 @@ static int ec_bhf_probe(struct pci_dev *dev, const struct pci_device_id *id)
 
        memcpy_fromio(net_dev->dev_addr, priv->mii_io + MII_MAC_ADDR, 6);
 
-       dev_dbg(&dev->dev, "CX5020 Ethercat master address: %pM\n",
-               net_dev->dev_addr);
-
        err = register_netdev(net_dev);
        if (err < 0)
                goto err_free_net_dev;
index 43e08d0bc3d316ff407555bf1ec170c44c3c2be2..a9f239adc3e3a7db481026e31367281ce6d1e6f5 100644 (file)
@@ -86,6 +86,8 @@ static inline char *nic_name(struct pci_dev *pdev)
 
 #define BE_MAX_JUMBO_FRAME_SIZE        9018
 #define BE_MIN_MTU             256
+#define BE_MAX_MTU              (BE_MAX_JUMBO_FRAME_SIZE -     \
+                                (ETH_HLEN + ETH_FCS_LEN))
 
 #define BE_NUM_VLANS_SUPPORTED 64
 #define BE_MAX_EQD             128u
@@ -112,7 +114,6 @@ static inline char *nic_name(struct pci_dev *pdev)
 #define MAX_ROCE_EQS           5
 #define MAX_MSIX_VECTORS       32
 #define MIN_MSIX_VECTORS       1
-#define BE_TX_BUDGET           256
 #define BE_NAPI_WEIGHT         64
 #define MAX_RX_POST            BE_NAPI_WEIGHT /* Frags posted at a time */
 #define RX_FRAGS_REFILL_WM     (RX_Q_LEN - MAX_RX_POST)
@@ -198,7 +199,6 @@ struct be_eq_obj {
 
        u8 idx;                 /* array index */
        u8 msix_idx;
-       u16 tx_budget;
        u16 spurious_intr;
        struct napi_struct napi;
        struct be_adapter *adapter;
@@ -248,6 +248,13 @@ struct be_tx_stats {
        ulong tx_jiffies;
        u32 tx_stops;
        u32 tx_drv_drops;       /* pkts dropped by driver */
+       /* the error counters are described in be_ethtool.c */
+       u32 tx_hdr_parse_err;
+       u32 tx_dma_err;
+       u32 tx_tso_err;
+       u32 tx_spoof_check_err;
+       u32 tx_qinq_err;
+       u32 tx_internal_parity_err;
        struct u64_stats_sync sync;
        struct u64_stats_sync sync_compl;
 };
@@ -316,6 +323,7 @@ struct be_rx_obj {
 struct be_drv_stats {
        u32 be_on_die_temperature;
        u32 eth_red_drops;
+       u32 dma_map_errors;
        u32 rx_drops_no_pbuf;
        u32 rx_drops_no_txpb;
        u32 rx_drops_no_erx_descr;
@@ -613,6 +621,10 @@ extern const struct ethtool_ops be_ethtool_ops;
        for (i = eqo->idx, rxo = &adapter->rx_obj[i]; i < adapter->num_rx_qs;\
                 i += adapter->num_evt_qs, rxo += adapter->num_evt_qs)
 
+#define for_all_tx_queues_on_eq(adapter, eqo, txo, i)                  \
+       for (i = eqo->idx, txo = &adapter->tx_obj[i]; i < adapter->num_tx_qs;\
+               i += adapter->num_evt_qs, txo += adapter->num_evt_qs)
+
 #define is_mcc_eqo(eqo)                        (eqo->idx == 0)
 #define mcc_eqo(adapter)               (&adapter->eq_obj[0])
 
@@ -661,6 +673,18 @@ static inline u32 amap_get(void *ptr, u32 dw_offset, u32 mask, u32 offset)
                        amap_mask(sizeof(((_struct *)0)->field)),       \
                        AMAP_BIT_OFFSET(_struct, field))
 
+#define GET_RX_COMPL_V0_BITS(field, ptr)                               \
+               AMAP_GET_BITS(struct amap_eth_rx_compl_v0, field, ptr)
+
+#define GET_RX_COMPL_V1_BITS(field, ptr)                               \
+               AMAP_GET_BITS(struct amap_eth_rx_compl_v1, field, ptr)
+
+#define GET_TX_COMPL_BITS(field, ptr)                                  \
+               AMAP_GET_BITS(struct amap_eth_tx_compl, field, ptr)
+
+#define SET_TX_WRB_HDR_BITS(field, ptr, val)                           \
+               AMAP_SET_BITS(struct amap_eth_hdr_wrb, field, ptr, val)
+
 #define be_dws_cpu_to_le(wrb, len)     swap_dws(wrb, len)
 #define be_dws_le_to_cpu(wrb, len)     swap_dws(wrb, len)
 static inline void swap_dws(void *wrb, int len)
index 4370ec1952accd2b3ce8ea3beda71ca35ba03331..5be100d1bc0ae4e935d302817a90dde5a91fe64d 100644 (file)
@@ -1681,17 +1681,17 @@ err:
        return status;
 }
 
-void be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf)
+int be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf)
 {
        struct be_dma_mem get_fat_cmd;
        struct be_mcc_wrb *wrb;
        struct be_cmd_req_get_fat *req;
        u32 offset = 0, total_size, buf_size,
                                log_offset = sizeof(u32), payload_len;
-       int status;
+       int status = 0;
 
        if (buf_len == 0)
-               return;
+               return -EIO;
 
        total_size = buf_len;
 
@@ -1700,10 +1700,9 @@ void be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf)
                                              get_fat_cmd.size,
                                              &get_fat_cmd.dma);
        if (!get_fat_cmd.va) {
-               status = -ENOMEM;
                dev_err(&adapter->pdev->dev,
                "Memory allocation failure while retrieving FAT data\n");
-               return;
+               return -ENOMEM;
        }
 
        spin_lock_bh(&adapter->mcc_lock);
@@ -1746,6 +1745,7 @@ err:
        pci_free_consistent(adapter->pdev, get_fat_cmd.size,
                            get_fat_cmd.va, get_fat_cmd.dma);
        spin_unlock_bh(&adapter->mcc_lock);
+       return status;
 }
 
 /* Uses synchronous mcc */
@@ -1771,6 +1771,7 @@ int be_cmd_get_fw_ver(struct be_adapter *adapter)
        status = be_mcc_notify_wait(adapter);
        if (!status) {
                struct be_cmd_resp_get_fw_version *resp = embedded_payload(wrb);
+
                strcpy(adapter->fw_ver, resp->firmware_version_string);
                strcpy(adapter->fw_on_flash, resp->fw_on_flash_version_string);
        }
@@ -2018,6 +2019,9 @@ int be_cmd_query_fw_cfg(struct be_adapter *adapter)
                adapter->function_mode = le32_to_cpu(resp->function_mode);
                adapter->function_caps = le32_to_cpu(resp->function_caps);
                adapter->asic_rev = le32_to_cpu(resp->asic_revision) & 0xFF;
+               dev_info(&adapter->pdev->dev,
+                        "FW config: function_mode=0x%x, function_caps=0x%x\n",
+                        adapter->function_mode, adapter->function_caps);
        }
 
        mutex_unlock(&adapter->mbox_lock);
index 5284b825bba28521b072c8b0891a3b36c3b464a6..0e1186856aa61ba9cef38e16fa14589fec8c11a0 100644 (file)
@@ -2101,7 +2101,7 @@ int be_cmd_get_die_temperature(struct be_adapter *adapter);
 int be_cmd_get_cntl_attributes(struct be_adapter *adapter);
 int be_cmd_req_native_mode(struct be_adapter *adapter);
 int be_cmd_get_reg_len(struct be_adapter *adapter, u32 *log_size);
-void be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf);
+int be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf);
 int be_cmd_get_fn_privileges(struct be_adapter *adapter, u32 *privilege,
                             u32 domain);
 int be_cmd_set_fn_privileges(struct be_adapter *adapter, u32 privileges,
index 0cd3311409a82a1aef601c66f46c3c72fc244070..2fd38261bedb17c7ff8118a7ea7b9f6af090791c 100644 (file)
@@ -78,6 +78,11 @@ static const struct be_ethtool_stat et_stats[] = {
         * fifo must never overflow.
         */
        {DRVSTAT_INFO(rxpp_fifo_overflow_drop)},
+       /* Received packets dropped when the RX block runs out of space in
+        * one of its input FIFOs. This could happen due a long burst of
+        * minimum-sized (64b) frames in the receive path.
+        * This counter may also be erroneously incremented rarely.
+        */
        {DRVSTAT_INFO(rx_input_fifo_overflow_drop)},
        {DRVSTAT_INFO(rx_ip_checksum_errs)},
        {DRVSTAT_INFO(rx_tcp_checksum_errs)},
@@ -114,6 +119,8 @@ static const struct be_ethtool_stat et_stats[] = {
         * is more than 9018 bytes
         */
        {DRVSTAT_INFO(rx_drops_mtu)},
+       /* Number of dma mapping errors */
+       {DRVSTAT_INFO(dma_map_errors)},
        /* Number of packets dropped due to random early drop function */
        {DRVSTAT_INFO(eth_red_drops)},
        {DRVSTAT_INFO(be_on_die_temperature)},
@@ -152,6 +159,34 @@ static const struct be_ethtool_stat et_rx_stats[] = {
  */
 static const struct be_ethtool_stat et_tx_stats[] = {
        {DRVSTAT_TX_INFO(tx_compl)}, /* If moving this member see above note */
+       /* This counter is incremented when the HW encounters an error while
+        * parsing the packet header of an outgoing TX request. This counter is
+        * applicable only for BE2, BE3 and Skyhawk based adapters.
+        */
+       {DRVSTAT_TX_INFO(tx_hdr_parse_err)},
+       /* This counter is incremented when an error occurs in the DMA
+        * operation associated with the TX request from the host to the device.
+        */
+       {DRVSTAT_TX_INFO(tx_dma_err)},
+       /* This counter is incremented when MAC or VLAN spoof checking is
+        * enabled on the interface and the TX request fails the spoof check
+        * in HW.
+        */
+       {DRVSTAT_TX_INFO(tx_spoof_check_err)},
+       /* This counter is incremented when the HW encounters an error while
+        * performing TSO offload. This counter is applicable only for Lancer
+        * adapters.
+        */
+       {DRVSTAT_TX_INFO(tx_tso_err)},
+       /* This counter is incremented when the HW detects Q-in-Q style VLAN
+        * tagging in a packet and such tagging is not expected on the outgoing
+        * interface. This counter is applicable only for Lancer adapters.
+        */
+       {DRVSTAT_TX_INFO(tx_qinq_err)},
+       /* This counter is incremented when the HW detects parity errors in the
+        * packet data. This counter is applicable only for Lancer adapters.
+        */
+       {DRVSTAT_TX_INFO(tx_internal_parity_err)},
        {DRVSTAT_TX_INFO(tx_bytes)},
        {DRVSTAT_TX_INFO(tx_pkts)},
        /* Number of skbs queued for trasmission by the driver */
index 8840c64aaeca7daca310d0a5a38dfdbed790fb12..295ee0835ba0bb32979d9923fd2db75f030e55a6 100644 (file)
@@ -315,6 +315,18 @@ struct be_eth_hdr_wrb {
        u32 dw[4];
 };
 
+/********* Tx Compl Status Encoding *********/
+#define BE_TX_COMP_HDR_PARSE_ERR       0x2
+#define BE_TX_COMP_NDMA_ERR            0x3
+#define BE_TX_COMP_ACL_ERR             0x5
+
+#define LANCER_TX_COMP_LSO_ERR                 0x1
+#define LANCER_TX_COMP_HSW_DROP_MAC_ERR                0x3
+#define LANCER_TX_COMP_HSW_DROP_VLAN_ERR       0x5
+#define LANCER_TX_COMP_QINQ_ERR                        0x7
+#define LANCER_TX_COMP_PARITY_ERR              0xb
+#define LANCER_TX_COMP_DMA_ERR                 0xd
+
 /* TX Compl Queue Descriptor */
 
 /* Pseudo amap definition for eth_tx_compl in which each bit of the
index 93ff8ef3935227c348d5bc8b20a6f0c4248ca570..5b26c4c9ab2b4fb2b98bb868a611bf5aeffb41a3 100644 (file)
@@ -738,38 +738,37 @@ static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr,
 
        memset(hdr, 0, sizeof(*hdr));
 
-       AMAP_SET_BITS(struct amap_eth_hdr_wrb, crc, hdr, 1);
+       SET_TX_WRB_HDR_BITS(crc, hdr, 1);
 
        if (skb_is_gso(skb)) {
-               AMAP_SET_BITS(struct amap_eth_hdr_wrb, lso, hdr, 1);
-               AMAP_SET_BITS(struct amap_eth_hdr_wrb, lso_mss,
-                       hdr, skb_shinfo(skb)->gso_size);
+               SET_TX_WRB_HDR_BITS(lso, hdr, 1);
+               SET_TX_WRB_HDR_BITS(lso_mss, hdr, skb_shinfo(skb)->gso_size);
                if (skb_is_gso_v6(skb) && !lancer_chip(adapter))
-                       AMAP_SET_BITS(struct amap_eth_hdr_wrb, lso6, hdr, 1);
+                       SET_TX_WRB_HDR_BITS(lso6, hdr, 1);
        } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
                if (skb->encapsulation) {
-                       AMAP_SET_BITS(struct amap_eth_hdr_wrb, ipcs, hdr, 1);
+                       SET_TX_WRB_HDR_BITS(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);
+                       SET_TX_WRB_HDR_BITS(tcpcs, hdr, 1);
                else if (proto == IPPROTO_UDP)
-                       AMAP_SET_BITS(struct amap_eth_hdr_wrb, udpcs, hdr, 1);
+                       SET_TX_WRB_HDR_BITS(udpcs, hdr, 1);
        }
 
        if (vlan_tx_tag_present(skb)) {
-               AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan, hdr, 1);
+               SET_TX_WRB_HDR_BITS(vlan, hdr, 1);
                vlan_tag = be_get_tx_vlan_tag(adapter, skb);
-               AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan_tag, hdr, vlan_tag);
+               SET_TX_WRB_HDR_BITS(vlan_tag, hdr, vlan_tag);
        }
 
        /* To skip HW VLAN tagging: evt = 1, compl = 0 */
-       AMAP_SET_BITS(struct amap_eth_hdr_wrb, complete, hdr, !skip_hw_vlan);
-       AMAP_SET_BITS(struct amap_eth_hdr_wrb, event, hdr, 1);
-       AMAP_SET_BITS(struct amap_eth_hdr_wrb, num_wrb, hdr, wrb_cnt);
-       AMAP_SET_BITS(struct amap_eth_hdr_wrb, len, hdr, len);
+       SET_TX_WRB_HDR_BITS(complete, hdr, !skip_hw_vlan);
+       SET_TX_WRB_HDR_BITS(event, hdr, 1);
+       SET_TX_WRB_HDR_BITS(num_wrb, hdr, wrb_cnt);
+       SET_TX_WRB_HDR_BITS(len, hdr, len);
 }
 
 static void unmap_tx_frag(struct device *dev, struct be_eth_wrb *wrb,
@@ -850,6 +849,7 @@ dma_err:
                unmap_tx_frag(dev, wrb, map_single);
                map_single = false;
                copied -= wrb->frag_len;
+               adapter->drv_stats.dma_map_errors++;
                queue_head_inc(txq);
        }
        return 0;
@@ -1073,15 +1073,15 @@ static netdev_tx_t be_xmit(struct sk_buff *skb, struct net_device *netdev)
 static int be_change_mtu(struct net_device *netdev, int new_mtu)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
-       if (new_mtu < BE_MIN_MTU ||
-           new_mtu > (BE_MAX_JUMBO_FRAME_SIZE - (ETH_HLEN + ETH_FCS_LEN))) {
-               dev_info(&adapter->pdev->dev,
-                        "MTU must be between %d and %d bytes\n",
-                        BE_MIN_MTU,
-                        (BE_MAX_JUMBO_FRAME_SIZE - (ETH_HLEN + ETH_FCS_LEN)));
+       struct device *dev = &adapter->pdev->dev;
+
+       if (new_mtu < BE_MIN_MTU || new_mtu > BE_MAX_MTU) {
+               dev_info(dev, "MTU must be between %d and %d bytes\n",
+                        BE_MIN_MTU, BE_MAX_MTU);
                return -EINVAL;
        }
-       dev_info(&adapter->pdev->dev, "MTU changed from %d to %d bytes\n",
+
+       dev_info(dev, "MTU changed from %d to %d bytes\n",
                 netdev->mtu, new_mtu);
        netdev->mtu = new_mtu;
        return 0;
@@ -1683,7 +1683,7 @@ static void be_rx_compl_process(struct be_rx_obj *rxo, struct napi_struct *napi,
        if (netdev->features & NETIF_F_RXHASH)
                skb_set_hash(skb, rxcp->rss_hash, PKT_HASH_TYPE_L3);
 
-       skb->encapsulation = rxcp->tunneled;
+       skb->csum_level = rxcp->tunneled;
        skb_mark_napi_id(skb, napi);
 
        if (rxcp->vlanf)
@@ -1741,7 +1741,7 @@ static void be_rx_compl_process_gro(struct be_rx_obj *rxo,
        if (adapter->netdev->features & NETIF_F_RXHASH)
                skb_set_hash(skb, rxcp->rss_hash, PKT_HASH_TYPE_L3);
 
-       skb->encapsulation = rxcp->tunneled;
+       skb->csum_level = rxcp->tunneled;
        skb_mark_napi_id(skb, napi);
 
        if (rxcp->vlanf)
@@ -1753,65 +1753,46 @@ static void be_rx_compl_process_gro(struct be_rx_obj *rxo,
 static void be_parse_rx_compl_v1(struct be_eth_rx_compl *compl,
                                 struct be_rx_compl_info *rxcp)
 {
-       rxcp->pkt_size =
-               AMAP_GET_BITS(struct amap_eth_rx_compl_v1, pktsize, compl);
-       rxcp->vlanf = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vtp, compl);
-       rxcp->err = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, err, compl);
-       rxcp->tcpf = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, tcpf, compl);
-       rxcp->udpf = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, udpf, compl);
-       rxcp->ip_csum =
-               AMAP_GET_BITS(struct amap_eth_rx_compl_v1, ipcksm, compl);
-       rxcp->l4_csum =
-               AMAP_GET_BITS(struct amap_eth_rx_compl_v1, l4_cksm, compl);
-       rxcp->ipv6 =
-               AMAP_GET_BITS(struct amap_eth_rx_compl_v1, ip_version, compl);
-       rxcp->num_rcvd =
-               AMAP_GET_BITS(struct amap_eth_rx_compl_v1, numfrags, compl);
-       rxcp->pkt_type =
-               AMAP_GET_BITS(struct amap_eth_rx_compl_v1, cast_enc, compl);
-       rxcp->rss_hash =
-               AMAP_GET_BITS(struct amap_eth_rx_compl_v1, rsshash, compl);
+       rxcp->pkt_size = GET_RX_COMPL_V1_BITS(pktsize, compl);
+       rxcp->vlanf = GET_RX_COMPL_V1_BITS(vtp, compl);
+       rxcp->err = GET_RX_COMPL_V1_BITS(err, compl);
+       rxcp->tcpf = GET_RX_COMPL_V1_BITS(tcpf, compl);
+       rxcp->udpf = GET_RX_COMPL_V1_BITS(udpf, compl);
+       rxcp->ip_csum = GET_RX_COMPL_V1_BITS(ipcksm, compl);
+       rxcp->l4_csum = GET_RX_COMPL_V1_BITS(l4_cksm, compl);
+       rxcp->ipv6 = GET_RX_COMPL_V1_BITS(ip_version, compl);
+       rxcp->num_rcvd = GET_RX_COMPL_V1_BITS(numfrags, compl);
+       rxcp->pkt_type = GET_RX_COMPL_V1_BITS(cast_enc, compl);
+       rxcp->rss_hash = GET_RX_COMPL_V1_BITS(rsshash, compl);
        if (rxcp->vlanf) {
-               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->qnq = GET_RX_COMPL_V1_BITS(qnq, compl);
+               rxcp->vlan_tag = GET_RX_COMPL_V1_BITS(vlan_tag, compl);
        }
-       rxcp->port = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, port, compl);
+       rxcp->port = GET_RX_COMPL_V1_BITS(port, compl);
        rxcp->tunneled =
-               AMAP_GET_BITS(struct amap_eth_rx_compl_v1, tunneled, compl);
+               GET_RX_COMPL_V1_BITS(tunneled, compl);
 }
 
 static void be_parse_rx_compl_v0(struct be_eth_rx_compl *compl,
                                 struct be_rx_compl_info *rxcp)
 {
-       rxcp->pkt_size =
-               AMAP_GET_BITS(struct amap_eth_rx_compl_v0, pktsize, compl);
-       rxcp->vlanf = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vtp, compl);
-       rxcp->err = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, err, compl);
-       rxcp->tcpf = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, tcpf, compl);
-       rxcp->udpf = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, udpf, compl);
-       rxcp->ip_csum =
-               AMAP_GET_BITS(struct amap_eth_rx_compl_v0, ipcksm, compl);
-       rxcp->l4_csum =
-               AMAP_GET_BITS(struct amap_eth_rx_compl_v0, l4_cksm, compl);
-       rxcp->ipv6 =
-               AMAP_GET_BITS(struct amap_eth_rx_compl_v0, ip_version, compl);
-       rxcp->num_rcvd =
-               AMAP_GET_BITS(struct amap_eth_rx_compl_v0, numfrags, compl);
-       rxcp->pkt_type =
-               AMAP_GET_BITS(struct amap_eth_rx_compl_v0, cast_enc, compl);
-       rxcp->rss_hash =
-               AMAP_GET_BITS(struct amap_eth_rx_compl_v0, rsshash, compl);
+       rxcp->pkt_size = GET_RX_COMPL_V0_BITS(pktsize, compl);
+       rxcp->vlanf = GET_RX_COMPL_V0_BITS(vtp, compl);
+       rxcp->err = GET_RX_COMPL_V0_BITS(err, compl);
+       rxcp->tcpf = GET_RX_COMPL_V0_BITS(tcpf, compl);
+       rxcp->udpf = GET_RX_COMPL_V0_BITS(udpf, compl);
+       rxcp->ip_csum = GET_RX_COMPL_V0_BITS(ipcksm, compl);
+       rxcp->l4_csum = GET_RX_COMPL_V0_BITS(l4_cksm, compl);
+       rxcp->ipv6 = GET_RX_COMPL_V0_BITS(ip_version, compl);
+       rxcp->num_rcvd = GET_RX_COMPL_V0_BITS(numfrags, compl);
+       rxcp->pkt_type = GET_RX_COMPL_V0_BITS(cast_enc, compl);
+       rxcp->rss_hash = GET_RX_COMPL_V0_BITS(rsshash, compl);
        if (rxcp->vlanf) {
-               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);
+               rxcp->qnq = GET_RX_COMPL_V0_BITS(qnq, compl);
+               rxcp->vlan_tag = GET_RX_COMPL_V0_BITS(vlan_tag, compl);
        }
-       rxcp->port = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, port, compl);
-       rxcp->ip_frag = AMAP_GET_BITS(struct amap_eth_rx_compl_v0,
-                                     ip_frag, compl);
+       rxcp->port = GET_RX_COMPL_V0_BITS(port, compl);
+       rxcp->ip_frag = GET_RX_COMPL_V0_BITS(ip_frag, compl);
 }
 
 static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo)
@@ -1897,7 +1878,7 @@ static void be_post_rx_frags(struct be_rx_obj *rxo, gfp_t gfp)
                        if (dma_mapping_error(dev, page_dmaaddr)) {
                                put_page(pagep);
                                pagep = NULL;
-                               rx_stats(rxo)->rx_post_fail++;
+                               adapter->drv_stats.dma_map_errors++;
                                break;
                        }
                        page_offset = 0;
@@ -1991,7 +1972,7 @@ static u16 be_tx_compl_process(struct be_adapter *adapter,
                queue_tail_inc(txq);
        } while (cur_index != last_index);
 
-       dev_kfree_skb_any(sent_skb);
+       dev_consume_skb_any(sent_skb);
        return num_wrbs;
 }
 
@@ -2091,9 +2072,7 @@ static void be_tx_compl_clean(struct be_adapter *adapter)
                        num_wrbs = 0;
                        txq = &txo->q;
                        while ((txcp = be_tx_compl_get(&txo->cq))) {
-                               end_idx =
-                                       AMAP_GET_BITS(struct amap_eth_tx_compl,
-                                                     wrb_index, txcp);
+                               end_idx = GET_TX_COMPL_BITS(wrb_index, txcp);
                                num_wrbs += be_tx_compl_process(adapter, txo,
                                                                end_idx);
                                cmpl++;
@@ -2164,7 +2143,6 @@ static int be_evt_queues_create(struct be_adapter *adapter)
                napi_hash_add(&eqo->napi);
                aic = &adapter->aic_obj[i];
                eqo->adapter = adapter;
-               eqo->tx_budget = BE_TX_BUDGET;
                eqo->idx = i;
                aic->max_eqd = BE_MAX_EQD;
                aic->enable = true;
@@ -2443,20 +2421,63 @@ loop_continue:
        return work_done;
 }
 
-static bool be_process_tx(struct be_adapter *adapter, struct be_tx_obj *txo,
-                         int budget, int idx)
+static inline void be_update_tx_err(struct be_tx_obj *txo, u32 status)
+{
+       switch (status) {
+       case BE_TX_COMP_HDR_PARSE_ERR:
+               tx_stats(txo)->tx_hdr_parse_err++;
+               break;
+       case BE_TX_COMP_NDMA_ERR:
+               tx_stats(txo)->tx_dma_err++;
+               break;
+       case BE_TX_COMP_ACL_ERR:
+               tx_stats(txo)->tx_spoof_check_err++;
+               break;
+       }
+}
+
+static inline void lancer_update_tx_err(struct be_tx_obj *txo, u32 status)
+{
+       switch (status) {
+       case LANCER_TX_COMP_LSO_ERR:
+               tx_stats(txo)->tx_tso_err++;
+               break;
+       case LANCER_TX_COMP_HSW_DROP_MAC_ERR:
+       case LANCER_TX_COMP_HSW_DROP_VLAN_ERR:
+               tx_stats(txo)->tx_spoof_check_err++;
+               break;
+       case LANCER_TX_COMP_QINQ_ERR:
+               tx_stats(txo)->tx_qinq_err++;
+               break;
+       case LANCER_TX_COMP_PARITY_ERR:
+               tx_stats(txo)->tx_internal_parity_err++;
+               break;
+       case LANCER_TX_COMP_DMA_ERR:
+               tx_stats(txo)->tx_dma_err++;
+               break;
+       }
+}
+
+static void be_process_tx(struct be_adapter *adapter, struct be_tx_obj *txo,
+                         int idx)
 {
        struct be_eth_tx_compl *txcp;
-       int num_wrbs = 0, work_done;
+       int num_wrbs = 0, work_done = 0;
+       u32 compl_status;
+       u16 last_idx;
 
-       for (work_done = 0; work_done < budget; work_done++) {
-               txcp = be_tx_compl_get(&txo->cq);
-               if (!txcp)
-                       break;
-               num_wrbs += be_tx_compl_process(adapter, txo,
-                                               AMAP_GET_BITS(struct
-                                                             amap_eth_tx_compl,
-                                                             wrb_index, txcp));
+       while ((txcp = be_tx_compl_get(&txo->cq))) {
+               last_idx = GET_TX_COMPL_BITS(wrb_index, txcp);
+               num_wrbs += be_tx_compl_process(adapter, txo, last_idx);
+               work_done++;
+
+               compl_status = GET_TX_COMPL_BITS(status, txcp);
+               if (compl_status) {
+                       if (lancer_chip(adapter))
+                               lancer_update_tx_err(txo, compl_status);
+                       else
+                               be_update_tx_err(txo, compl_status);
+               }
        }
 
        if (work_done) {
@@ -2474,7 +2495,6 @@ static bool be_process_tx(struct be_adapter *adapter, struct be_tx_obj *txo,
                tx_stats(txo)->tx_compl += work_done;
                u64_stats_update_end(&tx_stats(txo)->sync_compl);
        }
-       return (work_done < budget); /* Done */
 }
 
 int be_poll(struct napi_struct *napi, int budget)
@@ -2483,17 +2503,12 @@ int be_poll(struct napi_struct *napi, int budget)
        struct be_adapter *adapter = eqo->adapter;
        int max_work = 0, work, i, num_evts;
        struct be_rx_obj *rxo;
-       bool tx_done;
+       struct be_tx_obj *txo;
 
        num_evts = events_get(eqo);
 
-       /* Process all TXQs serviced by this EQ */
-       for (i = eqo->idx; i < adapter->num_tx_qs; i += adapter->num_evt_qs) {
-               tx_done = be_process_tx(adapter, &adapter->tx_obj[i],
-                                       eqo->tx_budget, i);
-               if (!tx_done)
-                       max_work = budget;
-       }
+       for_all_tx_queues_on_eq(adapter, eqo, txo, i)
+               be_process_tx(adapter, txo, i);
 
        if (be_lock_napi(eqo)) {
                /* This loop will iterate twice for EQ0 in which
@@ -3309,10 +3324,20 @@ static void BEx_get_resources(struct be_adapter *adapter,
         */
        if (BE2_chip(adapter) || use_sriov ||  (adapter->port_num > 1) ||
            !be_physfn(adapter) || (be_is_mc(adapter) &&
-           !(adapter->function_caps & BE_FUNCTION_CAPS_RSS)))
+           !(adapter->function_caps & BE_FUNCTION_CAPS_RSS))) {
                res->max_tx_qs = 1;
-       else
+       } else if (adapter->function_caps & BE_FUNCTION_CAPS_SUPER_NIC) {
+               struct be_resources super_nic_res = {0};
+
+               /* On a SuperNIC profile, the driver needs to use the
+                * GET_PROFILE_CONFIG cmd to query the per-function TXQ limits
+                */
+               be_cmd_get_profile_config(adapter, &super_nic_res, 0);
+               /* Some old versions of BE3 FW don't report max_tx_qs value */
+               res->max_tx_qs = super_nic_res.max_tx_qs ? : BE3_MAX_TX_QS;
+       } else {
                res->max_tx_qs = BE3_MAX_TX_QS;
+       }
 
        if ((adapter->function_caps & BE_FUNCTION_CAPS_RSS) &&
            !use_sriov && be_physfn(adapter))
@@ -3413,16 +3438,16 @@ static int be_get_resources(struct be_adapter *adapter)
                if (be_roce_supported(adapter))
                        res.max_evt_qs /= 2;
                adapter->res = res;
-
-               dev_info(dev, "Max: txqs %d, rxqs %d, rss %d, eqs %d, vfs %d\n",
-                        be_max_txqs(adapter), be_max_rxqs(adapter),
-                        be_max_rss(adapter), be_max_eqs(adapter),
-                        be_max_vfs(adapter));
-               dev_info(dev, "Max: uc-macs %d, mc-macs %d, vlans %d\n",
-                        be_max_uc(adapter), be_max_mc(adapter),
-                        be_max_vlans(adapter));
        }
 
+       dev_info(dev, "Max: txqs %d, rxqs %d, rss %d, eqs %d, vfs %d\n",
+                be_max_txqs(adapter), be_max_rxqs(adapter),
+                be_max_rss(adapter), be_max_eqs(adapter),
+                be_max_vfs(adapter));
+       dev_info(dev, "Max: uc-macs %d, mc-macs %d, vlans %d\n",
+                be_max_uc(adapter), be_max_mc(adapter),
+                be_max_vlans(adapter));
+
        return 0;
 }
 
@@ -3633,6 +3658,7 @@ static int be_setup(struct be_adapter *adapter)
                goto err;
 
        be_cmd_get_fw_ver(adapter);
+       dev_info(dev, "FW version is %s\n", adapter->fw_ver);
 
        if (BE2_chip(adapter) && fw_major_num(adapter->fw_ver) < 4) {
                dev_err(dev, "Firmware on card is old(%s), IRQs may not work.",
@@ -4052,6 +4078,7 @@ static int lancer_fw_download(struct be_adapter *adapter,
 {
 #define LANCER_FW_DOWNLOAD_CHUNK      (32 * 1024)
 #define LANCER_FW_DOWNLOAD_LOCATION   "/prg"
+       struct device *dev = &adapter->pdev->dev;
        struct be_dma_mem flash_cmd;
        const u8 *data_ptr = NULL;
        u8 *dest_image_ptr = NULL;
@@ -4064,21 +4091,16 @@ static int lancer_fw_download(struct be_adapter *adapter,
        u8 change_status;
 
        if (!IS_ALIGNED(fw->size, sizeof(u32))) {
-               dev_err(&adapter->pdev->dev,
-                       "FW Image not properly aligned. "
-                       "Length must be 4 byte aligned.\n");
-               status = -EINVAL;
-               goto lancer_fw_exit;
+               dev_err(dev, "FW image size should be multiple of 4\n");
+               return -EINVAL;
        }
 
        flash_cmd.size = sizeof(struct lancer_cmd_req_write_object)
                                + LANCER_FW_DOWNLOAD_CHUNK;
-       flash_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, flash_cmd.size,
+       flash_cmd.va = dma_alloc_coherent(dev, flash_cmd.size,
                                          &flash_cmd.dma, GFP_KERNEL);
-       if (!flash_cmd.va) {
-               status = -ENOMEM;
-               goto lancer_fw_exit;
-       }
+       if (!flash_cmd.va)
+               return -ENOMEM;
 
        dest_image_ptr = flash_cmd.va +
                                sizeof(struct lancer_cmd_req_write_object);
@@ -4113,35 +4135,27 @@ static int lancer_fw_download(struct be_adapter *adapter,
                                                 &add_status);
        }
 
-       dma_free_coherent(&adapter->pdev->dev, flash_cmd.size, flash_cmd.va,
-                         flash_cmd.dma);
+       dma_free_coherent(dev, flash_cmd.size, flash_cmd.va, flash_cmd.dma);
        if (status) {
-               dev_err(&adapter->pdev->dev,
-                       "Firmware load error. "
-                       "Status code: 0x%x Additional Status: 0x%x\n",
-                       status, add_status);
-               goto lancer_fw_exit;
+               dev_err(dev, "Firmware load error\n");
+               return be_cmd_status(status);
        }
 
+       dev_info(dev, "Firmware flashed successfully\n");
+
        if (change_status == LANCER_FW_RESET_NEEDED) {
-               dev_info(&adapter->pdev->dev,
-                        "Resetting adapter to activate new FW\n");
+               dev_info(dev, "Resetting adapter to activate new FW\n");
                status = lancer_physdev_ctrl(adapter,
                                             PHYSDEV_CONTROL_FW_RESET_MASK);
                if (status) {
-                       dev_err(&adapter->pdev->dev,
-                               "Adapter busy for FW reset.\n"
-                               "New FW will not be active.\n");
-                       goto lancer_fw_exit;
+                       dev_err(dev, "Adapter busy, could not reset FW\n");
+                       dev_err(dev, "Reboot server to activate new FW\n");
                }
        } else if (change_status != LANCER_NO_RESET_NEEDED) {
-               dev_err(&adapter->pdev->dev,
-                       "System reboot required for new FW to be active\n");
+               dev_info(dev, "Reboot server to activate new FW\n");
        }
 
-       dev_info(&adapter->pdev->dev, "Firmware flashed successfully\n");
-lancer_fw_exit:
-       return status;
+       return 0;
 }
 
 #define UFI_TYPE2              2
@@ -4506,6 +4520,7 @@ static int be_map_pci_bars(struct be_adapter *adapter)
        return 0;
 
 pci_map_err:
+       dev_err(&adapter->pdev->dev, "Error in mapping PCI BARs\n");
        be_unmap_pci_bars(adapter);
        return -ENOMEM;
 }
@@ -4822,6 +4837,8 @@ static int be_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id)
        struct net_device *netdev;
        char port_name;
 
+       dev_info(&pdev->dev, "%s version is %s\n", DRV_NAME, DRV_VER);
+
        status = pci_enable_device(pdev);
        if (status)
                goto do_none;
index 9f7fa644a397a57c21bfa317b9154f1bc5b8e2ee..ee41d98b44b6d685ccb7a2c4f3d62bea419c25ff 100644 (file)
@@ -275,6 +275,9 @@ struct fec_enet_private {
        struct clk *clk_enet_out;
        struct clk *clk_ptp;
 
+       bool ptp_clk_on;
+       struct mutex ptp_clk_mutex;
+
        /* The saved address of a sent-in-place packet/buffer, for skfree(). */
        unsigned char *tx_bounce[TX_RING_SIZE];
        struct  sk_buff *tx_skbuff[TX_RING_SIZE];
@@ -335,7 +338,7 @@ struct fec_enet_private {
        u32 cycle_speed;
        int hwts_rx_en;
        int hwts_tx_en;
-       struct timer_list time_keep;
+       struct delayed_work time_keep;
        struct regulator *reg_phy;
 };
 
index 4f87dffcb9b26688ba7ef51145138c88b8d6ad8a..89355a719625567789c5a2ed5a43df783fcad487 100644 (file)
@@ -1611,17 +1611,27 @@ static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
                                goto failed_clk_enet_out;
                }
                if (fep->clk_ptp) {
+                       mutex_lock(&fep->ptp_clk_mutex);
                        ret = clk_prepare_enable(fep->clk_ptp);
-                       if (ret)
+                       if (ret) {
+                               mutex_unlock(&fep->ptp_clk_mutex);
                                goto failed_clk_ptp;
+                       } else {
+                               fep->ptp_clk_on = true;
+                       }
+                       mutex_unlock(&fep->ptp_clk_mutex);
                }
        } else {
                clk_disable_unprepare(fep->clk_ahb);
                clk_disable_unprepare(fep->clk_ipg);
                if (fep->clk_enet_out)
                        clk_disable_unprepare(fep->clk_enet_out);
-               if (fep->clk_ptp)
+               if (fep->clk_ptp) {
+                       mutex_lock(&fep->ptp_clk_mutex);
                        clk_disable_unprepare(fep->clk_ptp);
+                       fep->ptp_clk_on = false;
+                       mutex_unlock(&fep->ptp_clk_mutex);
+               }
        }
 
        return 0;
@@ -2625,6 +2635,8 @@ fec_probe(struct platform_device *pdev)
        if (IS_ERR(fep->clk_enet_out))
                fep->clk_enet_out = NULL;
 
+       fep->ptp_clk_on = false;
+       mutex_init(&fep->ptp_clk_mutex);
        fep->clk_ptp = devm_clk_get(&pdev->dev, "ptp");
        fep->bufdesc_ex =
                pdev->id_entry->driver_data & FEC_QUIRK_HAS_BUFDESC_EX;
@@ -2715,10 +2727,10 @@ fec_drv_remove(struct platform_device *pdev)
        struct net_device *ndev = platform_get_drvdata(pdev);
        struct fec_enet_private *fep = netdev_priv(ndev);
 
+       cancel_delayed_work_sync(&fep->time_keep);
        cancel_work_sync(&fep->tx_timeout_work);
        unregister_netdev(ndev);
        fec_enet_mii_remove(fep);
-       del_timer_sync(&fep->time_keep);
        if (fep->reg_phy)
                regulator_disable(fep->reg_phy);
        if (fep->ptp_clock)
index 82386b29914a8640bd2e17f956bdd0946fc5c3ce..cca3617a2321fa22198658e83b1ee5d65176f298 100644 (file)
@@ -245,12 +245,20 @@ static int fec_ptp_settime(struct ptp_clock_info *ptp,
        u64 ns;
        unsigned long flags;
 
+       mutex_lock(&fep->ptp_clk_mutex);
+       /* Check the ptp clock */
+       if (!fep->ptp_clk_on) {
+               mutex_unlock(&fep->ptp_clk_mutex);
+               return -EINVAL;
+       }
+
        ns = ts->tv_sec * 1000000000ULL;
        ns += ts->tv_nsec;
 
        spin_lock_irqsave(&fep->tmreg_lock, flags);
        timecounter_init(&fep->tc, &fep->cc, ns);
        spin_unlock_irqrestore(&fep->tmreg_lock, flags);
+       mutex_unlock(&fep->ptp_clk_mutex);
        return 0;
 }
 
@@ -338,17 +346,22 @@ int fec_ptp_get(struct net_device *ndev, struct ifreq *ifr)
  * fec_time_keep - call timecounter_read every second to avoid timer overrun
  *                 because ENET just support 32bit counter, will timeout in 4s
  */
-static void fec_time_keep(unsigned long _data)
+static void fec_time_keep(struct work_struct *work)
 {
-       struct fec_enet_private *fep = (struct fec_enet_private *)_data;
+       struct delayed_work *dwork = to_delayed_work(work);
+       struct fec_enet_private *fep = container_of(dwork, struct fec_enet_private, time_keep);
        u64 ns;
        unsigned long flags;
 
-       spin_lock_irqsave(&fep->tmreg_lock, flags);
-       ns = timecounter_read(&fep->tc);
-       spin_unlock_irqrestore(&fep->tmreg_lock, flags);
+       mutex_lock(&fep->ptp_clk_mutex);
+       if (fep->ptp_clk_on) {
+               spin_lock_irqsave(&fep->tmreg_lock, flags);
+               ns = timecounter_read(&fep->tc);
+               spin_unlock_irqrestore(&fep->tmreg_lock, flags);
+       }
+       mutex_unlock(&fep->ptp_clk_mutex);
 
-       mod_timer(&fep->time_keep, jiffies + HZ);
+       schedule_delayed_work(&fep->time_keep, HZ);
 }
 
 /**
@@ -386,15 +399,13 @@ void fec_ptp_init(struct platform_device *pdev)
 
        fec_ptp_start_cyclecounter(ndev);
 
-       init_timer(&fep->time_keep);
-       fep->time_keep.data = (unsigned long)fep;
-       fep->time_keep.function = fec_time_keep;
-       fep->time_keep.expires = jiffies + HZ;
-       add_timer(&fep->time_keep);
+       INIT_DELAYED_WORK(&fep->time_keep, fec_time_keep);
 
        fep->ptp_clock = ptp_clock_register(&fep->ptp_caps, &pdev->dev);
        if (IS_ERR(fep->ptp_clock)) {
                fep->ptp_clock = NULL;
                pr_err("ptp_clock_register failed\n");
        }
+
+       schedule_delayed_work(&fep->time_keep, HZ);
 }
index ed7916f6fbcff0731118843123e5af2d351f5b64..76a6e0c77d69e1a01544a388b465e7e82ddbfd87 100644 (file)
@@ -1627,7 +1627,7 @@ static void hp100_clean_txring(struct net_device *dev)
 #endif
                /* Conversion to new PCI API : NOP */
                pci_unmap_single(lp->pci_dev, (dma_addr_t) lp->txrhead->pdl[1], lp->txrhead->pdl[2], PCI_DMA_TODEVICE);
-               dev_kfree_skb_any(lp->txrhead->skb);
+               dev_consume_skb_any(lp->txrhead->skb);
                lp->txrhead->skb = NULL;
                lp->txrhead = lp->txrhead->next;
                lp->txrcommit--;
@@ -1745,7 +1745,7 @@ static netdev_tx_t hp100_start_xmit(struct sk_buff *skb,
        hp100_ints_on();
        spin_unlock_irqrestore(&lp->lock, flags);
 
-       dev_kfree_skb_any(skb);
+       dev_consume_skb_any(skb);
 
 #ifdef HP100_DEBUG_TX
        printk("hp100: %s: start_xmit: end\n", dev->name);
index a0b418e007a0d09303a32838d8acf1a06ca9d061..566b17db135a306a2bb8eea0ce167a70e6e165f4 100644 (file)
@@ -1994,7 +1994,7 @@ static void xmit_common(struct sk_buff *skb, struct ehea_swqe *swqe)
 {
        swqe->tx_control |= EHEA_SWQE_IMM_DATA_PRESENT | EHEA_SWQE_CRC;
 
-       if (skb->protocol != htons(ETH_P_IP))
+       if (vlan_get_protocol(skb) != htons(ETH_P_IP))
                return;
 
        if (skb->ip_summed == CHECKSUM_PARTIAL)
index c9127562bd22cb51114249d35264bcbb679dcc3d..21978cc019e7c86dab83968ba994c0e9051c8e33 100644 (file)
@@ -292,6 +292,18 @@ failure:
        atomic_add(buffers_added, &(pool->available));
 }
 
+/*
+ * The final 8 bytes of the buffer list is a counter of frames dropped
+ * because there was not a buffer in the buffer list capable of holding
+ * the frame.
+ */
+static void ibmveth_update_rx_no_buffer(struct ibmveth_adapter *adapter)
+{
+       __be64 *p = adapter->buffer_list_addr + 4096 - 8;
+
+       adapter->rx_no_buffer = be64_to_cpup(p);
+}
+
 /* replenish routine */
 static void ibmveth_replenish_task(struct ibmveth_adapter *adapter)
 {
@@ -307,8 +319,7 @@ static void ibmveth_replenish_task(struct ibmveth_adapter *adapter)
                        ibmveth_replenish_buffer_pool(adapter, pool);
        }
 
-       adapter->rx_no_buffer = *(u64 *)(((char*)adapter->buffer_list_addr) +
-                                               4096 - 8);
+       ibmveth_update_rx_no_buffer(adapter);
 }
 
 /* empty and free ana buffer pool - also used to do cleanup in error paths */
@@ -698,8 +709,7 @@ static int ibmveth_close(struct net_device *netdev)
 
        free_irq(netdev->irq, netdev);
 
-       adapter->rx_no_buffer = *(u64 *)(((char *)adapter->buffer_list_addr) +
-                                               4096 - 8);
+       ibmveth_update_rx_no_buffer(adapter);
 
        ibmveth_cleanup(adapter);
 
index cca5bca44e737dd6fdd23e758bcffb8e2ce119e7..9b50272824a1e2c859feeaf00312aace09ec380c 100644 (file)
@@ -1,35 +1,30 @@
 /*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2006 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 - 2006 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 */
 
 #include "e1000.h"
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 
 enum {NETDEV_STATS, E1000_STATS};
 
@@ -42,7 +37,7 @@ struct e1000_stats {
 
 #define E1000_STAT(m)          E1000_STATS, \
                                sizeof(((struct e1000_adapter *)0)->m), \
-                               offsetof(struct e1000_adapter, m)
+                               offsetof(struct e1000_adapter, m)
 #define E1000_NETDEV_STAT(m)   NETDEV_STATS, \
                                sizeof(((struct net_device *)0)->m), \
                                offsetof(struct net_device, m)
@@ -104,6 +99,7 @@ static const char e1000_gstrings_test[][ETH_GSTRING_LEN] = {
        "Interrupt test (offline)", "Loopback test  (offline)",
        "Link test   (on/offline)"
 };
+
 #define E1000_TEST_LEN ARRAY_SIZE(e1000_gstrings_test)
 
 static int e1000_get_settings(struct net_device *netdev,
@@ -113,7 +109,6 @@ static int e1000_get_settings(struct net_device *netdev,
        struct e1000_hw *hw = &adapter->hw;
 
        if (hw->media_type == e1000_media_type_copper) {
-
                ecmd->supported = (SUPPORTED_10baseT_Half |
                                   SUPPORTED_10baseT_Full |
                                   SUPPORTED_100baseT_Half |
@@ -155,9 +150,8 @@ static int e1000_get_settings(struct net_device *netdev,
        }
 
        if (er32(STATUS) & E1000_STATUS_LU) {
-
                e1000_get_speed_and_duplex(hw, &adapter->link_speed,
-                                                  &adapter->link_duplex);
+                                          &adapter->link_duplex);
                ethtool_cmd_speed_set(ecmd, adapter->link_speed);
 
                /* unfortunately FULL_DUPLEX != DUPLEX_FULL
@@ -247,9 +241,9 @@ static int e1000_set_settings(struct net_device *netdev,
        if (netif_running(adapter->netdev)) {
                e1000_down(adapter);
                e1000_up(adapter);
-       } else
+       } else {
                e1000_reset(adapter);
-
+       }
        clear_bit(__E1000_RESETTING, &adapter->flags);
        return 0;
 }
@@ -279,11 +273,11 @@ static void e1000_get_pauseparam(struct net_device *netdev,
        pause->autoneg =
                (adapter->fc_autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE);
 
-       if (hw->fc == E1000_FC_RX_PAUSE)
+       if (hw->fc == E1000_FC_RX_PAUSE) {
                pause->rx_pause = 1;
-       else if (hw->fc == E1000_FC_TX_PAUSE)
+       } else if (hw->fc == E1000_FC_TX_PAUSE) {
                pause->tx_pause = 1;
-       else if (hw->fc == E1000_FC_FULL) {
+       else if (hw->fc == E1000_FC_FULL) {
                pause->rx_pause = 1;
                pause->tx_pause = 1;
        }
@@ -316,8 +310,9 @@ static int e1000_set_pauseparam(struct net_device *netdev,
                if (netif_running(adapter->netdev)) {
                        e1000_down(adapter);
                        e1000_up(adapter);
-               } else
+               } else {
                        e1000_reset(adapter);
+               }
        } else
                retval = ((hw->media_type == e1000_media_type_fiber) ?
                          e1000_setup_link(hw) : e1000_force_mac_fc(hw));
@@ -329,12 +324,14 @@ static int e1000_set_pauseparam(struct net_device *netdev,
 static u32 e1000_get_msglevel(struct net_device *netdev)
 {
        struct e1000_adapter *adapter = netdev_priv(netdev);
+
        return adapter->msg_enable;
 }
 
 static void e1000_set_msglevel(struct net_device *netdev, u32 data)
 {
        struct e1000_adapter *adapter = netdev_priv(netdev);
+
        adapter->msg_enable = data;
 }
 
@@ -526,7 +523,7 @@ static int e1000_set_eeprom(struct net_device *netdev,
                 * only the first byte of the word is being modified
                 */
                ret_val = e1000_read_eeprom(hw, last_word, 1,
-                                 &eeprom_buff[last_word - first_word]);
+                                           &eeprom_buff[last_word - first_word]);
        }
 
        /* Device's eeprom is always little-endian, word addressable */
@@ -618,13 +615,12 @@ static int e1000_set_ringparam(struct net_device *netdev,
        adapter->tx_ring = txdr;
        adapter->rx_ring = rxdr;
 
-       rxdr->count = max(ring->rx_pending,(u32)E1000_MIN_RXD);
-       rxdr->count = min(rxdr->count,(u32)(mac_type < e1000_82544 ?
+       rxdr->count = max(ring->rx_pending, (u32)E1000_MIN_RXD);
+       rxdr->count = min(rxdr->count, (u32)(mac_type < e1000_82544 ?
                          E1000_MAX_RXD : E1000_MAX_82544_RXD));
        rxdr->count = ALIGN(rxdr->count, REQ_RX_DESCRIPTOR_MULTIPLE);
-
-       txdr->count = max(ring->tx_pending,(u32)E1000_MIN_TXD);
-       txdr->count = min(txdr->count,(u32)(mac_type < e1000_82544 ?
+       txdr->count = max(ring->tx_pending, (u32)E1000_MIN_TXD);
+       txdr->count = min(txdr->count, (u32)(mac_type < e1000_82544 ?
                          E1000_MAX_TXD : E1000_MAX_82544_TXD));
        txdr->count = ALIGN(txdr->count, REQ_TX_DESCRIPTOR_MULTIPLE);
 
@@ -680,8 +676,9 @@ static bool reg_pattern_test(struct e1000_adapter *adapter, u64 *data, int reg,
                             u32 mask, u32 write)
 {
        struct e1000_hw *hw = &adapter->hw;
-       static const u32 test[] =
-               {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF};
+       static const u32 test[] = {
+               0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF
+       };
        u8 __iomem *address = hw->hw_addr + reg;
        u32 read;
        int i;
@@ -793,8 +790,8 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
                REG_PATTERN_TEST(TIDV, 0x0000FFFF, 0x0000FFFF);
                value = E1000_RAR_ENTRIES;
                for (i = 0; i < value; i++) {
-                       REG_PATTERN_TEST(RA + (((i << 1) + 1) << 2), 0x8003FFFF,
-                                        0xFFFFFFFF);
+                       REG_PATTERN_TEST(RA + (((i << 1) + 1) << 2),
+                                        0x8003FFFF, 0xFFFFFFFF);
                }
        } else {
                REG_SET_AND_CHECK(RCTL, 0xFFFFFFFF, 0x01FFFFFF);
@@ -877,7 +874,6 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
 
        /* Test each interrupt */
        for (; i < 10; i++) {
-
                /* Interrupt to test */
                mask = 1 << i;
 
@@ -1149,8 +1145,7 @@ static void e1000_phy_reset_clk_and_crs(struct e1000_adapter *adapter)
         */
        e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_reg);
        phy_reg |= M88E1000_EPSCR_TX_CLK_25;
-       e1000_write_phy_reg(hw,
-               M88E1000_EXT_PHY_SPEC_CTRL, phy_reg);
+       e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_reg);
 
        /* In addition, because of the s/w reset above, we need to enable
         * CRS on TX.  This must be set for both full and half duplex
@@ -1158,8 +1153,7 @@ static void e1000_phy_reset_clk_and_crs(struct e1000_adapter *adapter)
         */
        e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_reg);
        phy_reg |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
-       e1000_write_phy_reg(hw,
-               M88E1000_PHY_SPEC_CTRL, phy_reg);
+       e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_reg);
 }
 
 static int e1000_nonintegrated_phy_loopback(struct e1000_adapter *adapter)
@@ -1216,7 +1210,7 @@ static int e1000_nonintegrated_phy_loopback(struct e1000_adapter *adapter)
        /* Check Phy Configuration */
        e1000_read_phy_reg(hw, PHY_CTRL, &phy_reg);
        if (phy_reg != 0x4100)
-                return 9;
+               return 9;
 
        e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_reg);
        if (phy_reg != 0x0070)
@@ -1261,7 +1255,7 @@ static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter)
                        E1000_CTRL_FD); /* Force Duplex to FULL */
 
        if (hw->media_type == e1000_media_type_copper &&
-          hw->phy_type == e1000_phy_m88)
+           hw->phy_type == e1000_phy_m88)
                ctrl_reg |= E1000_CTRL_ILOS; /* Invert Loss of Signal */
        else {
                /* Set the ILOS bit on the fiber Nic is half
@@ -1299,7 +1293,7 @@ static int e1000_set_phy_loopback(struct e1000_adapter *adapter)
                         * attempt this 10 times.
                         */
                        while (e1000_nonintegrated_phy_loopback(adapter) &&
-                             count++ < 10);
+                              count++ < 10);
                        if (count < 11)
                                return 0;
                }
@@ -1348,8 +1342,9 @@ static int e1000_setup_loopback_test(struct e1000_adapter *adapter)
                        ew32(RCTL, rctl);
                        return 0;
                }
-       } else if (hw->media_type == e1000_media_type_copper)
+       } else if (hw->media_type == e1000_media_type_copper) {
                return e1000_set_phy_loopback(adapter);
+       }
 
        return 7;
 }
@@ -1395,9 +1390,9 @@ static int e1000_check_lbtest_frame(struct sk_buff *skb,
                                    unsigned int frame_size)
 {
        frame_size &= ~1;
-       if (*(skb->data + 3) == 0xFF) {
-               if ((*(skb->data + frame_size / 2 + 10) == 0xBE) &&
-                  (*(skb->data + frame_size / 2 + 12) == 0xAF)) {
+       if (skb->data[3] == 0xFF) {
+               if (skb->data[frame_size / 2 + 10] == 0xBE &&
+                   skb->data[frame_size / 2 + 12] == 0xAF) {
                        return 0;
                }
        }
@@ -1410,7 +1405,7 @@ static int e1000_run_loopback_test(struct e1000_adapter *adapter)
        struct e1000_tx_ring *txdr = &adapter->test_tx_ring;
        struct e1000_rx_ring *rxdr = &adapter->test_rx_ring;
        struct pci_dev *pdev = adapter->pdev;
-       int i, j, k, l, lc, good_cnt, ret_val=0;
+       int i, j, k, l, lc, good_cnt, ret_val = 0;
        unsigned long time;
 
        ew32(RDT, rxdr->count - 1);
@@ -1429,12 +1424,13 @@ static int e1000_run_loopback_test(struct e1000_adapter *adapter)
        for (j = 0; j <= lc; j++) { /* loop count loop */
                for (i = 0; i < 64; i++) { /* send the packets */
                        e1000_create_lbtest_frame(txdr->buffer_info[i].skb,
-                                       1024);
+                                                 1024);
                        dma_sync_single_for_device(&pdev->dev,
                                                   txdr->buffer_info[k].dma,
                                                   txdr->buffer_info[k].length,
                                                   DMA_TO_DEVICE);
-                       if (unlikely(++k == txdr->count)) k = 0;
+                       if (unlikely(++k == txdr->count))
+                               k = 0;
                }
                ew32(TDT, k);
                E1000_WRITE_FLUSH();
@@ -1452,7 +1448,8 @@ static int e1000_run_loopback_test(struct e1000_adapter *adapter)
                                        1024);
                        if (!ret_val)
                                good_cnt++;
-                       if (unlikely(++l == rxdr->count)) l = 0;
+                       if (unlikely(++l == rxdr->count))
+                               l = 0;
                        /* time + 20 msecs (200 msecs on 2.4) is more than
                         * enough time to complete the receives, if it's
                         * exceeded, break and error off
@@ -1494,6 +1491,7 @@ static int e1000_link_test(struct e1000_adapter *adapter, u64 *data)
        *data = 0;
        if (hw->media_type == e1000_media_type_internal_serdes) {
                int i = 0;
+
                hw->serdes_has_link = false;
 
                /* On some blade server designs, link establishment
@@ -1512,9 +1510,8 @@ static int e1000_link_test(struct e1000_adapter *adapter, u64 *data)
                if (hw->autoneg)  /* if auto_neg is set wait for it */
                        msleep(4000);
 
-               if (!(er32(STATUS) & E1000_STATUS_LU)) {
+               if (!(er32(STATUS) & E1000_STATUS_LU))
                        *data = 1;
-               }
        }
        return *data;
 }
@@ -1665,8 +1662,7 @@ static void e1000_get_wol(struct net_device *netdev,
        struct e1000_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
 
-       wol->supported = WAKE_UCAST | WAKE_MCAST |
-                        WAKE_BCAST | WAKE_MAGIC;
+       wol->supported = WAKE_UCAST | WAKE_MCAST | WAKE_BCAST | WAKE_MAGIC;
        wol->wolopts = 0;
 
        /* this function will set ->supported = 0 and return 1 if wol is not
@@ -1819,6 +1815,7 @@ static int e1000_set_coalesce(struct net_device *netdev,
 static int e1000_nway_reset(struct net_device *netdev)
 {
        struct e1000_adapter *adapter = netdev_priv(netdev);
+
        if (netif_running(netdev))
                e1000_reinit_locked(adapter);
        return 0;
@@ -1830,22 +1827,29 @@ static void e1000_get_ethtool_stats(struct net_device *netdev,
        struct e1000_adapter *adapter = netdev_priv(netdev);
        int i;
        char *p = NULL;
+       const struct e1000_stats *stat = e1000_gstrings_stats;
 
        e1000_update_stats(adapter);
        for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) {
-               switch (e1000_gstrings_stats[i].type) {
+               switch (stat->type) {
                case NETDEV_STATS:
-                       p = (char *) netdev +
-                                       e1000_gstrings_stats[i].stat_offset;
+                       p = (char *)netdev + stat->stat_offset;
                        break;
                case E1000_STATS:
-                       p = (char *) adapter +
-                                       e1000_gstrings_stats[i].stat_offset;
+                       p = (char *)adapter + stat->stat_offset;
+                       break;
+               default:
+                       WARN_ONCE(1, "Invalid E1000 stat type: %u index %d\n",
+                                 stat->type, i);
                        break;
                }
 
-               data[i] = (e1000_gstrings_stats[i].sizeof_stat ==
-                       sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
+               if (stat->sizeof_stat == sizeof(u64))
+                       data[i] = *(u64 *)p;
+               else
+                       data[i] = *(u32 *)p;
+
+               stat++;
        }
 /* BUG_ON(i != E1000_STATS_LEN); */
 }
@@ -1858,8 +1862,7 @@ static void e1000_get_strings(struct net_device *netdev, u32 stringset,
 
        switch (stringset) {
        case ETH_SS_TEST:
-               memcpy(data, *e1000_gstrings_test,
-                       sizeof(e1000_gstrings_test));
+               memcpy(data, e1000_gstrings_test, sizeof(e1000_gstrings_test));
                break;
        case ETH_SS_STATS:
                for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) {
index cbc330b301cdcfb8dd7e62695700a4e4ee2920e6..ad3d5d12173faea9992f9e46f74f57e21043b05d 100644 (file)
@@ -2674,7 +2674,8 @@ set_itr_now:
 #define E1000_TX_FLAGS_VLAN_SHIFT      16
 
 static int e1000_tso(struct e1000_adapter *adapter,
-                    struct e1000_tx_ring *tx_ring, struct sk_buff *skb)
+                    struct e1000_tx_ring *tx_ring, struct sk_buff *skb,
+                    __be16 protocol)
 {
        struct e1000_context_desc *context_desc;
        struct e1000_buffer *buffer_info;
@@ -2692,7 +2693,7 @@ static int e1000_tso(struct e1000_adapter *adapter,
 
                hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
                mss = skb_shinfo(skb)->gso_size;
-               if (skb->protocol == htons(ETH_P_IP)) {
+               if (protocol == htons(ETH_P_IP)) {
                        struct iphdr *iph = ip_hdr(skb);
                        iph->tot_len = 0;
                        iph->check = 0;
@@ -2702,7 +2703,7 @@ static int e1000_tso(struct e1000_adapter *adapter,
                                                                 0);
                        cmd_length = E1000_TXD_CMD_IP;
                        ipcse = skb_transport_offset(skb) - 1;
-               } else if (skb->protocol == htons(ETH_P_IPV6)) {
+               } else if (skb_is_gso_v6(skb)) {
                        ipv6_hdr(skb)->payload_len = 0;
                        tcp_hdr(skb)->check =
                                ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
@@ -2745,7 +2746,8 @@ static int e1000_tso(struct e1000_adapter *adapter,
 }
 
 static bool e1000_tx_csum(struct e1000_adapter *adapter,
-                         struct e1000_tx_ring *tx_ring, struct sk_buff *skb)
+                         struct e1000_tx_ring *tx_ring, struct sk_buff *skb,
+                         __be16 protocol)
 {
        struct e1000_context_desc *context_desc;
        struct e1000_buffer *buffer_info;
@@ -2756,7 +2758,7 @@ static bool e1000_tx_csum(struct e1000_adapter *adapter,
        if (skb->ip_summed != CHECKSUM_PARTIAL)
                return false;
 
-       switch (skb->protocol) {
+       switch (protocol) {
        case cpu_to_be16(ETH_P_IP):
                if (ip_hdr(skb)->protocol == IPPROTO_TCP)
                        cmd_len |= E1000_TXD_CMD_TCP;
@@ -3097,6 +3099,7 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
        int count = 0;
        int tso;
        unsigned int f;
+       __be16 protocol = vlan_get_protocol(skb);
 
        /* This goes back to the question of how to logically map a Tx queue
         * to a flow.  Right now, performance is impacted slightly negatively
@@ -3210,7 +3213,7 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
 
        first = tx_ring->next_to_use;
 
-       tso = e1000_tso(adapter, tx_ring, skb);
+       tso = e1000_tso(adapter, tx_ring, skb, protocol);
        if (tso < 0) {
                dev_kfree_skb_any(skb);
                return NETDEV_TX_OK;
@@ -3220,10 +3223,10 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
                if (likely(hw->mac_type != e1000_82544))
                        tx_ring->last_tx_tso = true;
                tx_flags |= E1000_TX_FLAGS_TSO;
-       } else if (likely(e1000_tx_csum(adapter, tx_ring, skb)))
+       } else if (likely(e1000_tx_csum(adapter, tx_ring, skb, protocol)))
                tx_flags |= E1000_TX_FLAGS_CSUM;
 
-       if (likely(skb->protocol == htons(ETH_P_IP)))
+       if (protocol == htons(ETH_P_IP))
                tx_flags |= E1000_TX_FLAGS_IPV4;
 
        if (unlikely(skb->no_fcs))
index 65c3aef2bd36a2ee01bab5a11649caa589b83c95..247335d2c7ec26cb9c50bb93c6a675b4ff35879a 100644 (file)
@@ -5164,7 +5164,8 @@ link_up:
 #define E1000_TX_FLAGS_VLAN_MASK       0xffff0000
 #define E1000_TX_FLAGS_VLAN_SHIFT      16
 
-static int e1000_tso(struct e1000_ring *tx_ring, struct sk_buff *skb)
+static int e1000_tso(struct e1000_ring *tx_ring, struct sk_buff *skb,
+                    __be16 protocol)
 {
        struct e1000_context_desc *context_desc;
        struct e1000_buffer *buffer_info;
@@ -5183,7 +5184,7 @@ static int e1000_tso(struct e1000_ring *tx_ring, struct sk_buff *skb)
 
        hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
        mss = skb_shinfo(skb)->gso_size;
-       if (skb->protocol == htons(ETH_P_IP)) {
+       if (protocol == htons(ETH_P_IP)) {
                struct iphdr *iph = ip_hdr(skb);
                iph->tot_len = 0;
                iph->check = 0;
@@ -5231,7 +5232,8 @@ static int e1000_tso(struct e1000_ring *tx_ring, struct sk_buff *skb)
        return 1;
 }
 
-static bool e1000_tx_csum(struct e1000_ring *tx_ring, struct sk_buff *skb)
+static bool e1000_tx_csum(struct e1000_ring *tx_ring, struct sk_buff *skb,
+                         __be16 protocol)
 {
        struct e1000_adapter *adapter = tx_ring->adapter;
        struct e1000_context_desc *context_desc;
@@ -5239,16 +5241,10 @@ static bool e1000_tx_csum(struct e1000_ring *tx_ring, struct sk_buff *skb)
        unsigned int i;
        u8 css;
        u32 cmd_len = E1000_TXD_CMD_DEXT;
-       __be16 protocol;
 
        if (skb->ip_summed != CHECKSUM_PARTIAL)
                return false;
 
-       if (skb->protocol == cpu_to_be16(ETH_P_8021Q))
-               protocol = vlan_eth_hdr(skb)->h_vlan_encapsulated_proto;
-       else
-               protocol = skb->protocol;
-
        switch (protocol) {
        case cpu_to_be16(ETH_P_IP):
                if (ip_hdr(skb)->protocol == IPPROTO_TCP)
@@ -5546,6 +5542,7 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
        int count = 0;
        int tso;
        unsigned int f;
+       __be16 protocol = vlan_get_protocol(skb);
 
        if (test_bit(__E1000_DOWN, &adapter->state)) {
                dev_kfree_skb_any(skb);
@@ -5620,7 +5617,7 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
 
        first = tx_ring->next_to_use;
 
-       tso = e1000_tso(tx_ring, skb);
+       tso = e1000_tso(tx_ring, skb, protocol);
        if (tso < 0) {
                dev_kfree_skb_any(skb);
                return NETDEV_TX_OK;
@@ -5628,14 +5625,14 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
 
        if (tso)
                tx_flags |= E1000_TX_FLAGS_TSO;
-       else if (e1000_tx_csum(tx_ring, skb))
+       else if (e1000_tx_csum(tx_ring, skb, protocol))
                tx_flags |= E1000_TX_FLAGS_CSUM;
 
        /* Old method was to assume IPv4 packet by default if TSO was enabled.
         * 82571 hardware supports TSO capabilities for IPv6 as well...
         * no longer assume, we must.
         */
-       if (skb->protocol == htons(ETH_P_IP))
+       if (protocol == htons(ETH_P_IP))
                tx_flags |= E1000_TX_FLAGS_IPV4;
 
        if (unlikely(skb->no_fcs))
index 801da392a20e23dc84e176579720f0a106695776..f1e33f896439b1d6ccbc5f2428d9aef05fcbcee3 100644 (file)
@@ -144,6 +144,8 @@ enum i40e_state_t {
        __I40E_PTP_TX_IN_PROGRESS,
        __I40E_BAD_EEPROM,
        __I40E_DOWN_REQUESTED,
+       __I40E_FD_FLUSH_REQUESTED,
+       __I40E_RESET_FAILED,
 };
 
 enum i40e_interrupt_policy {
@@ -250,6 +252,11 @@ struct i40e_pf {
        u16 fdir_pf_active_filters;
        u16 fd_sb_cnt_idx;
        u16 fd_atr_cnt_idx;
+       unsigned long fd_flush_timestamp;
+       u32 fd_flush_cnt;
+       u32 fd_add_err;
+       u32 fd_atr_cnt;
+       u32 fd_tcp_rule;
 
 #ifdef CONFIG_I40E_VXLAN
        __be16  vxlan_ports[I40E_MAX_PF_UDP_OFFLOAD_PORTS];
@@ -310,6 +317,7 @@ struct i40e_pf {
        u32 tx_timeout_count;
        u32 tx_timeout_recovery_level;
        unsigned long tx_timeout_last_recovery;
+       u32 tx_sluggish_count;
        u32 hw_csum_rx_error;
        u32 led_status;
        u16 corer_count; /* Core reset count */
@@ -608,6 +616,7 @@ int i40e_add_del_fdir(struct i40e_vsi *vsi,
 void i40e_fdir_check_and_reenable(struct i40e_pf *pf);
 int i40e_get_current_fd_count(struct i40e_pf *pf);
 int i40e_get_cur_guaranteed_fd_count(struct i40e_pf *pf);
+int i40e_get_current_atr_cnt(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,
index b29c157b1f57b7d587f00ff208a0124991d06bdb..72f5d25a222f0769ea514d5789407a543e66c3c2 100644 (file)
@@ -840,7 +840,8 @@ i40e_status i40e_asq_send_command(struct i40e_hw *hw,
 
        /* bump the tail */
        i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: desc and buffer:\n");
-       i40e_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc_on_ring, buff);
+       i40e_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc_on_ring,
+                     buff, buff_size);
        (hw->aq.asq.next_to_use)++;
        if (hw->aq.asq.next_to_use == hw->aq.asq.count)
                hw->aq.asq.next_to_use = 0;
@@ -891,7 +892,7 @@ i40e_status i40e_asq_send_command(struct i40e_hw *hw,
 
        i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE,
                   "AQTX: desc and buffer writeback:\n");
-       i40e_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, buff);
+       i40e_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, buff, buff_size);
 
        /* update the error if time out occurred */
        if ((!cmd_completed) &&
@@ -987,7 +988,8 @@ i40e_status i40e_clean_arq_element(struct i40e_hw *hw,
                       e->msg_size);
 
        i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQRX: desc and buffer:\n");
-       i40e_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, e->msg_buf);
+       i40e_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, e->msg_buf,
+                     hw->aq.arq_buf_size);
 
        /* Restore the original datalen and buffer address in the desc,
         * FW updates datalen to indicate the event message
index df43e7c6777c238423af02e9171bf418ad08e339..30056b25d94e6c331d9456c7171e3b51b5b7e754 100644 (file)
@@ -75,13 +75,15 @@ static i40e_status i40e_set_mac_type(struct i40e_hw *hw)
  * @mask: debug mask
  * @desc: pointer to admin queue descriptor
  * @buffer: pointer to command buffer
+ * @buf_len: max length of buffer
  *
  * Dumps debug log about adminq command with descriptor contents.
  **/
 void i40e_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask, void *desc,
-                  void *buffer)
+                  void *buffer, u16 buf_len)
 {
        struct i40e_aq_desc *aq_desc = (struct i40e_aq_desc *)desc;
+       u16 len = le16_to_cpu(aq_desc->datalen);
        u8 *aq_buffer = (u8 *)buffer;
        u32 data[4];
        u32 i = 0;
@@ -105,7 +107,9 @@ void i40e_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask, void *desc,
        if ((buffer != NULL) && (aq_desc->datalen != 0)) {
                memset(data, 0, sizeof(data));
                i40e_debug(hw, mask, "AQ CMD Buffer:\n");
-               for (i = 0; i < le16_to_cpu(aq_desc->datalen); i++) {
+               if (buf_len < len)
+                       len = buf_len;
+               for (i = 0; i < len; i++) {
                        data[((i % 16) / 4)] |=
                                ((u32)aq_buffer[i]) << (8 * (i % 4));
                        if ((i % 16) == 15) {
@@ -748,6 +752,8 @@ static enum i40e_media_type i40e_get_media_type(struct i40e_hw *hw)
        switch (hw->phy.link_info.phy_type) {
        case I40E_PHY_TYPE_10GBASE_SR:
        case I40E_PHY_TYPE_10GBASE_LR:
+       case I40E_PHY_TYPE_1000BASE_SX:
+       case I40E_PHY_TYPE_1000BASE_LX:
        case I40E_PHY_TYPE_40GBASE_SR4:
        case I40E_PHY_TYPE_40GBASE_LR4:
                media = I40E_MEDIA_TYPE_FIBER;
index 5a0cabeb35ed7f21e37a523a1418981fb23d0836..7067f4b9159c99e9720484ca2ea5d7fe574fed5f 100644 (file)
@@ -1356,6 +1356,9 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
                                 "emp reset count: %d\n", pf->empr_count);
                        dev_info(&pf->pdev->dev,
                                 "pf reset count: %d\n", pf->pfr_count);
+                       dev_info(&pf->pdev->dev,
+                                "pf tx sluggish count: %d\n",
+                                pf->tx_sluggish_count);
                } else if (strncmp(&cmd_buf[5], "port", 4) == 0) {
                        struct i40e_aqc_query_port_ets_config_resp *bw_data;
                        struct i40e_dcbx_config *cfg =
index e8ba7470700af1abaaf33826c7bffc8409666b9e..1dda467ae1ac62bdc5428e4c6086c322fdac597d 100644 (file)
@@ -145,6 +145,7 @@ static struct i40e_stats i40e_gstrings_stats[] = {
        I40E_PF_STAT("rx_jabber", stats.rx_jabber),
        I40E_PF_STAT("VF_admin_queue_requests", vf_aq_requests),
        I40E_PF_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared),
+       I40E_PF_STAT("fdir_flush_cnt", fd_flush_cnt),
        I40E_PF_STAT("fdir_atr_match", stats.fd_atr_match),
        I40E_PF_STAT("fdir_sb_match", stats.fd_sb_match),
 
@@ -312,7 +313,10 @@ static int i40e_get_settings(struct net_device *netdev,
                break;
        case I40E_PHY_TYPE_10GBASE_SR:
        case I40E_PHY_TYPE_10GBASE_LR:
+       case I40E_PHY_TYPE_1000BASE_SX:
+       case I40E_PHY_TYPE_1000BASE_LX:
                ecmd->supported = SUPPORTED_10000baseT_Full;
+               ecmd->supported |= SUPPORTED_1000baseT_Full;
                break;
        case I40E_PHY_TYPE_10GBASE_CR1_CU:
        case I40E_PHY_TYPE_10GBASE_CR1:
@@ -351,7 +355,8 @@ static int i40e_get_settings(struct net_device *netdev,
                break;
        default:
                /* if we got here and link is up something bad is afoot */
-               WARN_ON(link_up);
+               netdev_info(netdev, "WARNING: Link is up but PHY type 0x%x is not recognized.\n",
+                           hw_link_info->phy_type);
        }
 
 no_valid_phy_type:
@@ -461,7 +466,8 @@ static int i40e_set_settings(struct net_device *netdev,
 
        if (hw->phy.media_type != I40E_MEDIA_TYPE_BASET &&
            hw->phy.media_type != I40E_MEDIA_TYPE_FIBER &&
-           hw->phy.media_type != I40E_MEDIA_TYPE_BACKPLANE)
+           hw->phy.media_type != I40E_MEDIA_TYPE_BACKPLANE &&
+           hw->phy.link_info.link_info & I40E_AQ_LINK_UP)
                return -EOPNOTSUPP;
 
        /* get our own copy of the bits to check against */
@@ -492,11 +498,10 @@ static int i40e_set_settings(struct net_device *netdev,
        if (status)
                return -EAGAIN;
 
-       /* Copy link_speed and abilities to config in case they are not
+       /* Copy abilities to config in case autoneg is not
         * set below
         */
        memset(&config, 0, sizeof(struct i40e_aq_set_phy_config));
-       config.link_speed = abilities.link_speed;
        config.abilities = abilities.abilities;
 
        /* Check autoneg */
@@ -533,42 +538,38 @@ static int i40e_set_settings(struct net_device *netdev,
                return -EINVAL;
 
        if (advertise & ADVERTISED_100baseT_Full)
-               if (!(abilities.link_speed & I40E_LINK_SPEED_100MB)) {
-                       config.link_speed |= I40E_LINK_SPEED_100MB;
-                       change = true;
-               }
+               config.link_speed |= I40E_LINK_SPEED_100MB;
        if (advertise & ADVERTISED_1000baseT_Full ||
            advertise & ADVERTISED_1000baseKX_Full)
-               if (!(abilities.link_speed & I40E_LINK_SPEED_1GB)) {
-                       config.link_speed |= I40E_LINK_SPEED_1GB;
-                       change = true;
-               }
+               config.link_speed |= I40E_LINK_SPEED_1GB;
        if (advertise & ADVERTISED_10000baseT_Full ||
            advertise & ADVERTISED_10000baseKX4_Full ||
            advertise & ADVERTISED_10000baseKR_Full)
-               if (!(abilities.link_speed & I40E_LINK_SPEED_10GB)) {
-                       config.link_speed |= I40E_LINK_SPEED_10GB;
-                       change = true;
-               }
+               config.link_speed |= I40E_LINK_SPEED_10GB;
        if (advertise & ADVERTISED_40000baseKR4_Full ||
            advertise & ADVERTISED_40000baseCR4_Full ||
            advertise & ADVERTISED_40000baseSR4_Full ||
            advertise & ADVERTISED_40000baseLR4_Full)
-               if (!(abilities.link_speed & I40E_LINK_SPEED_40GB)) {
-                       config.link_speed |= I40E_LINK_SPEED_40GB;
-                       change = true;
-               }
+               config.link_speed |= I40E_LINK_SPEED_40GB;
 
-       if (change) {
+       if (change || (abilities.link_speed != config.link_speed)) {
                /* copy over the rest of the abilities */
                config.phy_type = abilities.phy_type;
                config.eee_capability = abilities.eee_capability;
                config.eeer = abilities.eeer_val;
                config.low_power_ctrl = abilities.d3_lpan;
 
-               /* If link is up set link and an so changes take effect */
-               if (hw->phy.link_info.link_info & I40E_AQ_LINK_UP)
-                       config.abilities |= I40E_AQ_PHY_ENABLE_ATOMIC_LINK;
+               /* set link and auto negotiation so changes take effect */
+               config.abilities |= I40E_AQ_PHY_ENABLE_ATOMIC_LINK;
+               /* If link is up put link down */
+               if (hw->phy.link_info.link_info & I40E_AQ_LINK_UP) {
+                       /* Tell the OS link is going down, the link will go
+                        * back up when fw says it is ready asynchronously
+                        */
+                       netdev_info(netdev, "PHY settings change requested, NIC Link is going down.\n");
+                       netif_carrier_off(netdev);
+                       netif_tx_stop_all_queues(netdev);
+               }
 
                /* make the aq call */
                status = i40e_aq_set_phy_config(hw, &config, NULL);
@@ -685,6 +686,13 @@ static int i40e_set_pauseparam(struct net_device *netdev,
        else
                 return -EINVAL;
 
+       /* Tell the OS link is going down, the link will go back up when fw
+        * says it is ready asynchronously
+        */
+       netdev_info(netdev, "Flow control settings change requested, NIC Link is going down.\n");
+       netif_carrier_off(netdev);
+       netif_tx_stop_all_queues(netdev);
+
        /* Set the fc mode and only restart an if link is up*/
        status = i40e_set_fc(hw, &aq_failures, link_up);
 
@@ -1977,6 +1985,13 @@ static int i40e_del_fdir_entry(struct i40e_vsi *vsi,
        struct i40e_pf *pf = vsi->back;
        int ret = 0;
 
+       if (test_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state) ||
+           test_bit(__I40E_RESET_INTR_RECEIVED, &pf->state))
+               return -EBUSY;
+
+       if (test_bit(__I40E_FD_FLUSH_REQUESTED, &pf->state))
+               return -EBUSY;
+
        ret = i40e_update_ethtool_fdir_entry(vsi, NULL, fsp->location, cmd);
 
        i40e_fdir_check_and_reenable(pf);
@@ -2010,6 +2025,13 @@ static int i40e_add_fdir_ethtool(struct i40e_vsi *vsi,
        if (pf->auto_disable_flags & I40E_FLAG_FD_SB_ENABLED)
                return -ENOSPC;
 
+       if (test_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state) ||
+           test_bit(__I40E_RESET_INTR_RECEIVED, &pf->state))
+               return -EBUSY;
+
+       if (test_bit(__I40E_FD_FLUSH_REQUESTED, &pf->state))
+               return -EBUSY;
+
        fsp = (struct ethtool_rx_flow_spec *)&cmd->fs;
 
        if (fsp->location >= (pf->hw.func_caps.fd_filters_best_effort +
index eddec6ba095b7105118962438c9914d40acd97b4..ed5f1c15fb0f4cd5fe7ce797920fd3b6cd21f7df 100644 (file)
@@ -37,9 +37,9 @@ static const char i40e_driver_string[] =
 
 #define DRV_KERN "-k"
 
-#define DRV_VERSION_MAJOR 0
-#define DRV_VERSION_MINOR 4
-#define DRV_VERSION_BUILD 21
+#define DRV_VERSION_MAJOR 1
+#define DRV_VERSION_MINOR 0
+#define DRV_VERSION_BUILD 11
 #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \
             __stringify(DRV_VERSION_MINOR) "." \
             __stringify(DRV_VERSION_BUILD)    DRV_KERN
@@ -1239,8 +1239,11 @@ struct i40e_mac_filter *i40e_put_mac_in_vlan(struct i40e_vsi *vsi, u8 *macaddr,
  * i40e_rm_default_mac_filter - Remove the default MAC filter set by NVM
  * @vsi: the PF Main VSI - inappropriate for any other VSI
  * @macaddr: the MAC address
+ *
+ * Some older firmware configurations set up a default promiscuous VLAN
+ * filter that needs to be removed.
  **/
-static void i40e_rm_default_mac_filter(struct i40e_vsi *vsi, u8 *macaddr)
+static int i40e_rm_default_mac_filter(struct i40e_vsi *vsi, u8 *macaddr)
 {
        struct i40e_aqc_remove_macvlan_element_data element;
        struct i40e_pf *pf = vsi->back;
@@ -1248,15 +1251,18 @@ static void i40e_rm_default_mac_filter(struct i40e_vsi *vsi, u8 *macaddr)
 
        /* Only appropriate for the PF main VSI */
        if (vsi->type != I40E_VSI_MAIN)
-               return;
+               return -EINVAL;
 
+       memset(&element, 0, sizeof(element));
        ether_addr_copy(element.mac_addr, macaddr);
        element.vlan_tag = 0;
        element.flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH |
                        I40E_AQC_MACVLAN_DEL_IGNORE_VLAN;
        aq_ret = i40e_aq_remove_macvlan(&pf->hw, vsi->seid, &element, 1, NULL);
        if (aq_ret)
-               dev_err(&pf->pdev->dev, "Could not remove default MAC-VLAN\n");
+               return -ENOENT;
+
+       return 0;
 }
 
 /**
@@ -1385,18 +1391,30 @@ static int i40e_set_mac(struct net_device *netdev, void *p)
 {
        struct i40e_netdev_priv *np = netdev_priv(netdev);
        struct i40e_vsi *vsi = np->vsi;
+       struct i40e_pf *pf = vsi->back;
+       struct i40e_hw *hw = &pf->hw;
        struct sockaddr *addr = p;
        struct i40e_mac_filter *f;
 
        if (!is_valid_ether_addr(addr->sa_data))
                return -EADDRNOTAVAIL;
 
-       netdev_info(netdev, "set mac address=%pM\n", addr->sa_data);
+       if (ether_addr_equal(netdev->dev_addr, addr->sa_data)) {
+               netdev_info(netdev, "already using mac address %pM\n",
+                           addr->sa_data);
+               return 0;
+       }
 
        if (test_bit(__I40E_DOWN, &vsi->back->state) ||
            test_bit(__I40E_RESET_RECOVERY_PENDING, &vsi->back->state))
                return -EADDRNOTAVAIL;
 
+       if (ether_addr_equal(hw->mac.addr, addr->sa_data))
+               netdev_info(netdev, "returning to hw mac address %pM\n",
+                           hw->mac.addr);
+       else
+               netdev_info(netdev, "set new mac address %pM\n", addr->sa_data);
+
        if (vsi->type == I40E_VSI_MAIN) {
                i40e_status ret;
                ret = i40e_aq_mac_address_write(&vsi->back->hw,
@@ -1410,25 +1428,34 @@ static int i40e_set_mac(struct net_device *netdev, void *p)
                }
        }
 
-       f = i40e_find_mac(vsi, addr->sa_data, false, true);
-       if (!f) {
-               /* In order to be sure to not drop any packets, add the
-                * new address first then delete the old one.
-                */
-               f = i40e_add_filter(vsi, addr->sa_data, I40E_VLAN_ANY,
-                                   false, false);
-               if (!f)
-                       return -ENOMEM;
+       if (ether_addr_equal(netdev->dev_addr, hw->mac.addr)) {
+               struct i40e_aqc_remove_macvlan_element_data element;
 
-               i40e_sync_vsi_filters(vsi);
+               memset(&element, 0, sizeof(element));
+               ether_addr_copy(element.mac_addr, netdev->dev_addr);
+               element.flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH;
+               i40e_aq_remove_macvlan(&pf->hw, vsi->seid, &element, 1, NULL);
+       } else {
                i40e_del_filter(vsi, netdev->dev_addr, I40E_VLAN_ANY,
                                false, false);
-               i40e_sync_vsi_filters(vsi);
        }
 
-       f->is_laa = true;
-       if (!ether_addr_equal(netdev->dev_addr, addr->sa_data))
-               ether_addr_copy(netdev->dev_addr, addr->sa_data);
+       if (ether_addr_equal(addr->sa_data, hw->mac.addr)) {
+               struct i40e_aqc_add_macvlan_element_data element;
+
+               memset(&element, 0, sizeof(element));
+               ether_addr_copy(element.mac_addr, hw->mac.addr);
+               element.flags = cpu_to_le16(I40E_AQC_MACVLAN_ADD_PERFECT_MATCH);
+               i40e_aq_add_macvlan(&pf->hw, vsi->seid, &element, 1, NULL);
+       } else {
+               f = i40e_add_filter(vsi, addr->sa_data, I40E_VLAN_ANY,
+                                   false, false);
+               if (f)
+                       f->is_laa = true;
+       }
+
+       i40e_sync_vsi_filters(vsi);
+       ether_addr_copy(netdev->dev_addr, addr->sa_data);
 
        return 0;
 }
@@ -1796,9 +1823,8 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
                kfree(add_list);
                add_list = NULL;
 
-               if (add_happened && (!aq_ret)) {
-                       /* do nothing */;
-               } else if (add_happened && (aq_ret)) {
+               if (add_happened && aq_ret &&
+                   pf->hw.aq.asq_last_status != I40E_AQ_RC_EINVAL) {
                        dev_info(&pf->pdev->dev,
                                 "add filter failed, err %d, aq_err %d\n",
                                 aq_ret, pf->hw.aq.asq_last_status);
@@ -4480,11 +4506,26 @@ static int i40e_up_complete(struct i40e_vsi *vsi)
                netif_carrier_on(vsi->netdev);
        } else if (vsi->netdev) {
                i40e_print_link_message(vsi, false);
+               /* need to check for qualified module here*/
+               if ((pf->hw.phy.link_info.link_info &
+                       I40E_AQ_MEDIA_AVAILABLE) &&
+                   (!(pf->hw.phy.link_info.an_info &
+                       I40E_AQ_QUALIFIED_MODULE)))
+                       netdev_err(vsi->netdev,
+                                  "the driver failed to link because an unqualified module was detected.");
        }
 
        /* replay FDIR SB filters */
-       if (vsi->type == I40E_VSI_FDIR)
+       if (vsi->type == I40E_VSI_FDIR) {
+               /* reset fd counters */
+               pf->fd_add_err = pf->fd_atr_cnt = 0;
+               if (pf->fd_tcp_rule > 0) {
+                       pf->flags &= ~I40E_FLAG_FD_ATR_ENABLED;
+                       dev_info(&pf->pdev->dev, "Forcing ATR off, sideband rules for TCP/IPv4 exist\n");
+                       pf->fd_tcp_rule = 0;
+               }
                i40e_fdir_filter_restore(vsi);
+       }
        i40e_service_event_schedule(pf);
 
        return 0;
@@ -5125,6 +5166,7 @@ int i40e_get_current_fd_count(struct i40e_pf *pf)
                      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
@@ -5133,15 +5175,17 @@ void i40e_fdir_check_and_reenable(struct i40e_pf *pf)
 {
        u32 fcnt_prog, fcnt_avail;
 
+       if (test_bit(__I40E_FD_FLUSH_REQUESTED, &pf->state))
+               return;
+
        /* 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_cur_guaranteed_fd_count(pf);
        fcnt_avail = pf->fdir_pf_filter_count;
-       if (fcnt_prog < (fcnt_avail - I40E_FDIR_BUFFER_HEAD_ROOM)) {
+       if ((fcnt_prog < (fcnt_avail - I40E_FDIR_BUFFER_HEAD_ROOM)) ||
+           (pf->fd_add_err == 0) ||
+           (i40e_get_current_atr_cnt(pf) < pf->fd_atr_cnt)) {
                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;
@@ -5158,23 +5202,84 @@ void i40e_fdir_check_and_reenable(struct i40e_pf *pf)
        }
 }
 
+#define I40E_MIN_FD_FLUSH_INTERVAL 10
+/**
+ * i40e_fdir_flush_and_replay - Function to flush all FD filters and replay SB
+ * @pf: board private structure
+ **/
+static void i40e_fdir_flush_and_replay(struct i40e_pf *pf)
+{
+       int flush_wait_retry = 50;
+       int reg;
+
+       if (time_after(jiffies, pf->fd_flush_timestamp +
+                               (I40E_MIN_FD_FLUSH_INTERVAL * HZ))) {
+               set_bit(__I40E_FD_FLUSH_REQUESTED, &pf->state);
+               pf->fd_flush_timestamp = jiffies;
+               pf->auto_disable_flags |= I40E_FLAG_FD_SB_ENABLED;
+               pf->flags &= ~I40E_FLAG_FD_ATR_ENABLED;
+               /* flush all filters */
+               wr32(&pf->hw, I40E_PFQF_CTL_1,
+                    I40E_PFQF_CTL_1_CLEARFDTABLE_MASK);
+               i40e_flush(&pf->hw);
+               pf->fd_flush_cnt++;
+               pf->fd_add_err = 0;
+               do {
+                       /* Check FD flush status every 5-6msec */
+                       usleep_range(5000, 6000);
+                       reg = rd32(&pf->hw, I40E_PFQF_CTL_1);
+                       if (!(reg & I40E_PFQF_CTL_1_CLEARFDTABLE_MASK))
+                               break;
+               } while (flush_wait_retry--);
+               if (reg & I40E_PFQF_CTL_1_CLEARFDTABLE_MASK) {
+                       dev_warn(&pf->pdev->dev, "FD table did not flush, needs more time\n");
+               } else {
+                       /* replay sideband filters */
+                       i40e_fdir_filter_restore(pf->vsi[pf->lan_vsi]);
+
+                       pf->flags |= I40E_FLAG_FD_ATR_ENABLED;
+                       pf->auto_disable_flags &= ~I40E_FLAG_FD_ATR_ENABLED;
+                       pf->auto_disable_flags &= ~I40E_FLAG_FD_SB_ENABLED;
+                       clear_bit(__I40E_FD_FLUSH_REQUESTED, &pf->state);
+                       dev_info(&pf->pdev->dev, "FD Filter table flushed and FD-SB replayed.\n");
+               }
+       }
+}
+
+/**
+ * i40e_get_current_atr_count - Get the count of total FD ATR filters programmed
+ * @pf: board private structure
+ **/
+int i40e_get_current_atr_cnt(struct i40e_pf *pf)
+{
+       return i40e_get_current_fd_count(pf) - pf->fdir_pf_active_filters;
+}
+
+/* We can see up to 256 filter programming desc in transit if the filters are
+ * being applied really fast; before we see the first
+ * filter miss error on Rx queue 0. Accumulating enough error messages before
+ * reacting will make sure we don't cause flush too often.
+ */
+#define I40E_MAX_FD_PROGRAM_ERROR 256
+
 /**
  * i40e_fdir_reinit_subtask - Worker thread to reinit FDIR filter table
  * @pf: board private structure
  **/
 static void i40e_fdir_reinit_subtask(struct i40e_pf *pf)
 {
-       if (!(pf->flags & I40E_FLAG_FDIR_REQUIRES_REINIT))
-               return;
 
        /* if interface is down do nothing */
        if (test_bit(__I40E_DOWN, &pf->state))
                return;
+
+       if ((pf->fd_add_err >= I40E_MAX_FD_PROGRAM_ERROR) &&
+           (i40e_get_current_atr_cnt(pf) >= pf->fd_atr_cnt) &&
+           (i40e_get_current_atr_cnt(pf) > pf->fdir_pf_filter_count))
+               i40e_fdir_flush_and_replay(pf);
+
        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;
 }
 
 /**
@@ -5184,7 +5289,7 @@ static void i40e_fdir_reinit_subtask(struct i40e_pf *pf)
  **/
 static void i40e_vsi_link_event(struct i40e_vsi *vsi, bool link_up)
 {
-       if (!vsi)
+       if (!vsi || test_bit(__I40E_DOWN, &vsi->state))
                return;
 
        switch (vsi->type) {
@@ -5420,6 +5525,13 @@ static void i40e_handle_link_event(struct i40e_pf *pf,
        memcpy(&pf->hw.phy.link_info_old, hw_link_info,
               sizeof(pf->hw.phy.link_info_old));
 
+       /* check for unqualified module, if link is down */
+       if ((status->link_info & I40E_AQ_MEDIA_AVAILABLE) &&
+           (!(status->an_info & I40E_AQ_QUALIFIED_MODULE)) &&
+           (!(status->link_info & I40E_AQ_LINK_UP)))
+               dev_err(&pf->pdev->dev,
+                       "The driver failed to link because an unqualified module was detected.\n");
+
        /* update link status */
        hw_link_info->phy_type = (enum i40e_aq_phy_type)status->phy_type;
        hw_link_info->link_speed = (enum i40e_aq_link_speed)status->link_speed;
@@ -5456,6 +5568,10 @@ static void i40e_clean_adminq_subtask(struct i40e_pf *pf)
        u32 oldval;
        u32 val;
 
+       /* Do not run clean AQ when PF reset fails */
+       if (test_bit(__I40E_RESET_FAILED, &pf->state))
+               return;
+
        /* check for error indications */
        val = rd32(&pf->hw, pf->hw.aq.arq.len);
        oldval = val;
@@ -5861,19 +5977,20 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit)
        ret = i40e_pf_reset(hw);
        if (ret) {
                dev_info(&pf->pdev->dev, "PF reset failed, %d\n", ret);
-               goto end_core_reset;
+               set_bit(__I40E_RESET_FAILED, &pf->state);
+               goto clear_recovery;
        }
        pf->pfr_count++;
 
        if (test_bit(__I40E_DOWN, &pf->state))
-               goto end_core_reset;
+               goto clear_recovery;
        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);
        if (ret) {
                dev_info(&pf->pdev->dev, "Rebuild AdminQ failed, %d\n", ret);
-               goto end_core_reset;
+               goto clear_recovery;
        }
 
        /* re-verify the eeprom if we just had an EMP reset */
@@ -5991,6 +6108,8 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit)
        i40e_send_version(pf);
 
 end_core_reset:
+       clear_bit(__I40E_RESET_FAILED, &pf->state);
+clear_recovery:
        clear_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state);
 }
 
@@ -6036,9 +6155,9 @@ static void i40e_handle_mdd_event(struct i40e_pf *pf)
                                I40E_GL_MDET_TX_EVENT_SHIFT;
                u8 queue = (reg & I40E_GL_MDET_TX_QUEUE_MASK) >>
                                I40E_GL_MDET_TX_QUEUE_SHIFT;
-               dev_info(&pf->pdev->dev,
-                        "Malicious Driver Detection event 0x%02x on TX queue %d pf number 0x%02x vf number 0x%02x\n",
-                        event, queue, pf_num, vf_num);
+               if (netif_msg_tx_err(pf))
+                       dev_info(&pf->pdev->dev, "Malicious Driver Detection event 0x%02x on TX queue %d pf number 0x%02x vf number 0x%02x\n",
+                                event, queue, pf_num, vf_num);
                wr32(hw, I40E_GL_MDET_TX, 0xffffffff);
                mdd_detected = true;
        }
@@ -6050,9 +6169,9 @@ static void i40e_handle_mdd_event(struct i40e_pf *pf)
                                I40E_GL_MDET_RX_EVENT_SHIFT;
                u8 queue = (reg & I40E_GL_MDET_RX_QUEUE_MASK) >>
                                I40E_GL_MDET_RX_QUEUE_SHIFT;
-               dev_info(&pf->pdev->dev,
-                        "Malicious Driver Detection event 0x%02x on RX queue %d of function 0x%02x\n",
-                        event, queue, func);
+               if (netif_msg_rx_err(pf))
+                       dev_info(&pf->pdev->dev, "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;
        }
@@ -6061,17 +6180,13 @@ static void i40e_handle_mdd_event(struct i40e_pf *pf)
                reg = rd32(hw, I40E_PF_MDET_TX);
                if (reg & I40E_PF_MDET_TX_VALID_MASK) {
                        wr32(hw, I40E_PF_MDET_TX, 0xFFFF);
-                       dev_info(&pf->pdev->dev,
-                                "MDD TX event is for this function 0x%08x, requesting PF reset.\n",
-                                reg);
+                       dev_info(&pf->pdev->dev, "TX driver issue detected, PF reset issued\n");
                        pf_mdd_detected = true;
                }
                reg = rd32(hw, I40E_PF_MDET_RX);
                if (reg & I40E_PF_MDET_RX_VALID_MASK) {
                        wr32(hw, I40E_PF_MDET_RX, 0xFFFF);
-                       dev_info(&pf->pdev->dev,
-                                "MDD RX event is for this function 0x%08x, requesting PF reset.\n",
-                                reg);
+                       dev_info(&pf->pdev->dev, "RX driver issue detected, PF reset issued\n");
                        pf_mdd_detected = true;
                }
                /* Queue belongs to the PF, initiate a reset */
@@ -6088,14 +6203,16 @@ static void i40e_handle_mdd_event(struct i40e_pf *pf)
                if (reg & I40E_VP_MDET_TX_VALID_MASK) {
                        wr32(hw, I40E_VP_MDET_TX(i), 0xFFFF);
                        vf->num_mdd_events++;
-                       dev_info(&pf->pdev->dev, "MDD TX event on VF %d\n", i);
+                       dev_info(&pf->pdev->dev, "TX driver issue detected on VF %d\n",
+                                i);
                }
 
                reg = rd32(hw, I40E_VP_MDET_RX(i));
                if (reg & I40E_VP_MDET_RX_VALID_MASK) {
                        wr32(hw, I40E_VP_MDET_RX(i), 0xFFFF);
                        vf->num_mdd_events++;
-                       dev_info(&pf->pdev->dev, "MDD RX event on VF %d\n", i);
+                       dev_info(&pf->pdev->dev, "RX driver issue detected on VF %d\n",
+                                i);
                }
 
                if (vf->num_mdd_events > I40E_DEFAULT_NUM_MDD_EVENTS_ALLOWED) {
@@ -7086,6 +7203,11 @@ bool i40e_set_ntuple(struct i40e_pf *pf, netdev_features_t features)
                }
                pf->flags &= ~I40E_FLAG_FD_SB_ENABLED;
                pf->auto_disable_flags &= ~I40E_FLAG_FD_SB_ENABLED;
+               /* reset fd counters */
+               pf->fd_add_err = pf->fd_atr_cnt = pf->fd_tcp_rule = 0;
+               pf->fdir_pf_active_filters = 0;
+               pf->flags |= I40E_FLAG_FD_ATR_ENABLED;
+               dev_info(&pf->pdev->dev, "ATR re-enabled.\n");
                /* if ATR was auto disabled it can be re-enabled. */
                if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
                    (pf->auto_disable_flags & I40E_FLAG_FD_ATR_ENABLED))
@@ -7352,7 +7474,7 @@ static const struct net_device_ops i40e_netdev_ops = {
        .ndo_set_vf_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,
-       .ndo_set_vf_spoofchk    = i40e_ndo_set_vf_spoofck,
+       .ndo_set_vf_spoofchk    = i40e_ndo_set_vf_spoofchk,
 #ifdef CONFIG_I40E_VXLAN
        .ndo_add_vxlan_port     = i40e_add_vxlan_port,
        .ndo_del_vxlan_port     = i40e_del_vxlan_port,
@@ -7421,14 +7543,14 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)
        if (vsi->type == I40E_VSI_MAIN) {
                SET_NETDEV_DEV(netdev, &pf->pdev->dev);
                ether_addr_copy(mac_addr, hw->mac.perm_addr);
-               /* The following two steps are necessary to prevent reception
-                * of tagged packets - by default the NVM loads a MAC-VLAN
-                * filter that will accept any tagged packet.  This is to
-                * prevent that during normal operations until a specific
-                * VLAN tag filter has been set.
+               /* The following steps are necessary to prevent reception
+                * of tagged packets - some older NVM configurations load a
+                * default a MAC-VLAN filter that accepts any tagged packet
+                * which must be replaced by a normal filter.
                 */
-               i40e_rm_default_mac_filter(vsi, mac_addr);
-               i40e_add_filter(vsi, mac_addr, I40E_VLAN_ANY, false, true);
+               if (!i40e_rm_default_mac_filter(vsi, mac_addr))
+                       i40e_add_filter(vsi, mac_addr,
+                                       I40E_VLAN_ANY, false, true);
        } else {
                /* relate the VSI_VMDQ name to the VSI_MAIN name */
                snprintf(netdev->name, IFNAMSIZ, "%sv%%d",
@@ -7644,7 +7766,22 @@ static int i40e_add_vsi(struct i40e_vsi *vsi)
                f_count++;
 
                if (f->is_laa && vsi->type == I40E_VSI_MAIN) {
-                       i40e_aq_mac_address_write(&vsi->back->hw,
+                       struct i40e_aqc_remove_macvlan_element_data element;
+
+                       memset(&element, 0, sizeof(element));
+                       ether_addr_copy(element.mac_addr, f->macaddr);
+                       element.flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH;
+                       ret = i40e_aq_remove_macvlan(hw, vsi->seid,
+                                                    &element, 1, NULL);
+                       if (ret) {
+                               /* some older FW has a different default */
+                               element.flags |=
+                                              I40E_AQC_MACVLAN_DEL_IGNORE_VLAN;
+                               i40e_aq_remove_macvlan(hw, vsi->seid,
+                                                      &element, 1, NULL);
+                       }
+
+                       i40e_aq_mac_address_write(hw,
                                                  I40E_AQC_WRITE_TYPE_LAA_WOL,
                                                  f->macaddr, NULL);
                }
index 949a9a01778b9c17aad87a78af9a933ac191856a..0988b5c1fe87d080e950f146c4c0c0b8ae231189 100644 (file)
@@ -52,10 +52,8 @@ i40e_status i40e_asq_send_command(struct i40e_hw *hw,
                                struct i40e_asq_cmd_details *cmd_details);
 
 /* debug function for adminq */
-void i40e_debug_aq(struct i40e_hw *hw,
-                  enum i40e_debug_mask mask,
-                  void *desc,
-                  void *buffer);
+void i40e_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask,
+                  void *desc, void *buffer, u16 buf_len);
 
 void i40e_idle_aq(struct i40e_hw *hw);
 bool i40e_check_asq_alive(struct i40e_hw *hw);
index bb7fe98b3a6cd7bd3c99d7454186f19451e84f1d..537b6216971d3b77c9ca169f01e2f6aaeb1f2ad1 100644 (file)
@@ -247,7 +247,7 @@ void i40e_ptp_rx_hang(struct i40e_vsi *vsi)
        u32 prttsyn_stat;
        int n;
 
-       if (pf->flags & I40E_FLAG_PTP)
+       if (!(pf->flags & I40E_FLAG_PTP))
                return;
 
        prttsyn_stat = rd32(hw, I40E_PRTTSYN_STAT_1);
index a51aa37b7b5af10a5204c1ef8329ce9229b1ce57..be039dd6114d5378b5896e6e58d1d10eb0578ca4 100644 (file)
@@ -224,15 +224,19 @@ static int i40e_add_del_fdir_udpv4(struct i40e_vsi *vsi,
        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);
+                        "PCTYPE:%d, Filter command send failed for fd_id:%d (ret = %d)\n",
+                        fd_data->pctype, fd_data->fd_id, ret);
                err = true;
        } else {
-               dev_info(&pf->pdev->dev,
-                        "Filter OK for PCTYPE %d (ret = %d)\n",
-                        fd_data->pctype, ret);
+               if (add)
+                       dev_info(&pf->pdev->dev,
+                                "Filter OK for PCTYPE %d loc = %d\n",
+                                fd_data->pctype, fd_data->fd_id);
+               else
+                       dev_info(&pf->pdev->dev,
+                                "Filter deleted for PCTYPE %d loc = %d\n",
+                                fd_data->pctype, fd_data->fd_id);
        }
-
        return err ? -EOPNOTSUPP : 0;
 }
 
@@ -276,10 +280,18 @@ static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi,
        tcp->source = fd_data->src_port;
 
        if (add) {
+               pf->fd_tcp_rule++;
                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;
                }
+       } else {
+               pf->fd_tcp_rule = (pf->fd_tcp_rule > 0) ?
+                                 (pf->fd_tcp_rule - 1) : 0;
+               if (pf->fd_tcp_rule == 0) {
+                       pf->flags |= I40E_FLAG_FD_ATR_ENABLED;
+                       dev_info(&pf->pdev->dev, "ATR re-enabled due to no sideband TCP/IPv4 rules\n");
+               }
        }
 
        fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP;
@@ -287,12 +299,17 @@ static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi,
 
        if (ret) {
                dev_info(&pf->pdev->dev,
-                        "Filter command send failed for PCTYPE %d (ret = %d)\n",
-                        fd_data->pctype, ret);
+                        "PCTYPE:%d, Filter command send failed for fd_id:%d (ret = %d)\n",
+                        fd_data->pctype, fd_data->fd_id, ret);
                err = true;
        } else {
-               dev_info(&pf->pdev->dev, "Filter OK for PCTYPE %d (ret = %d)\n",
-                        fd_data->pctype, ret);
+               if (add)
+                       dev_info(&pf->pdev->dev, "Filter OK for PCTYPE %d loc = %d)\n",
+                                fd_data->pctype, fd_data->fd_id);
+               else
+                       dev_info(&pf->pdev->dev,
+                                "Filter deleted for PCTYPE %d loc = %d\n",
+                                fd_data->pctype, fd_data->fd_id);
        }
 
        return err ? -EOPNOTSUPP : 0;
@@ -355,13 +372,18 @@ static int i40e_add_del_fdir_ipv4(struct i40e_vsi *vsi,
 
                if (ret) {
                        dev_info(&pf->pdev->dev,
-                                "Filter command send failed for PCTYPE %d (ret = %d)\n",
-                                fd_data->pctype, ret);
+                                "PCTYPE:%d, Filter command send failed for fd_id:%d (ret = %d)\n",
+                                fd_data->pctype, fd_data->fd_id, ret);
                        err = true;
                } else {
-                       dev_info(&pf->pdev->dev,
-                                "Filter OK for PCTYPE %d (ret = %d)\n",
-                                fd_data->pctype, ret);
+                       if (add)
+                               dev_info(&pf->pdev->dev,
+                                        "Filter OK for PCTYPE %d loc = %d\n",
+                                        fd_data->pctype, fd_data->fd_id);
+                       else
+                               dev_info(&pf->pdev->dev,
+                                        "Filter deleted for PCTYPE %d loc = %d\n",
+                                        fd_data->pctype, fd_data->fd_id);
                }
        }
 
@@ -443,8 +465,14 @@ static void i40e_fd_handle_status(struct i40e_ring *rx_ring,
                I40E_RX_PROG_STATUS_DESC_QW1_ERROR_SHIFT;
 
        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);
+               if ((rx_desc->wb.qword0.hi_dword.fd_id != 0) ||
+                   (I40E_DEBUG_FD & pf->hw.debug_mask))
+                       dev_warn(&pdev->dev, "ntuple filter loc = %d, could not be added\n",
+                                rx_desc->wb.qword0.hi_dword.fd_id);
+
+               pf->fd_add_err++;
+               /* store the current atr filter count */
+               pf->fd_atr_cnt = i40e_get_current_atr_cnt(pf);
 
                /* filter programming failed most likely due to table full */
                fcnt_prog = i40e_get_cur_guaranteed_fd_count(pf);
@@ -454,29 +482,21 @@ static void i40e_fd_handle_status(struct i40e_ring *rx_ring,
                 * 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) &&
+                       if ((pf->flags & I40E_FLAG_FD_SB_ENABLED) &&
                            !(pf->auto_disable_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->auto_disable_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\n");
+                       dev_info(&pdev->dev,
+                               "FD filter programming failed due to incorrect filter parameters\n");
                }
        } 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",
+                       dev_info(&pdev->dev, "ntuple filter fd_id = %d, could not be removed\n",
                                 rx_desc->wb.qword0.hi_dword.fd_id);
        }
 }
@@ -587,6 +607,7 @@ static u32 i40e_get_tx_pending(struct i40e_ring *ring)
 static bool i40e_check_tx_hang(struct i40e_ring *tx_ring)
 {
        u32 tx_pending = i40e_get_tx_pending(tx_ring);
+       struct i40e_pf *pf = tx_ring->vsi->back;
        bool ret = false;
 
        clear_check_for_tx_hang(tx_ring);
@@ -603,10 +624,17 @@ static bool i40e_check_tx_hang(struct i40e_ring *tx_ring)
         * pending but without time to complete it yet.
         */
        if ((tx_ring->tx_stats.tx_done_old == tx_ring->stats.packets) &&
-           tx_pending) {
+           (tx_pending >= I40E_MIN_DESC_PENDING)) {
                /* make sure it is true for two checks in a row */
                ret = test_and_set_bit(__I40E_HANG_CHECK_ARMED,
                                       &tx_ring->state);
+       } else if ((tx_ring->tx_stats.tx_done_old == tx_ring->stats.packets) &&
+                  (tx_pending < I40E_MIN_DESC_PENDING) &&
+                  (tx_pending > 0)) {
+               if (I40E_DEBUG_FLOW & pf->hw.debug_mask)
+                       dev_info(tx_ring->dev, "HW needs some more descs to do a cacheline flush. tx_pending %d, queue %d",
+                                tx_pending, tx_ring->queue_index);
+               pf->tx_sluggish_count++;
        } else {
                /* update completed stats and disarm the hang check */
                tx_ring->tx_stats.tx_done_old = tx_ring->stats.packets;
@@ -1213,7 +1241,6 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
        ipv6_tunnel = (rx_ptype > I40E_RX_PTYPE_GRENAT6_MAC_PAY3) &&
                      (rx_ptype < I40E_RX_PTYPE_GRENAT6_MACVLAN_IPV6_ICMP_PAY4);
 
-       skb->encapsulation = ipv4_tunnel || ipv6_tunnel;
        skb->ip_summed = CHECKSUM_NONE;
 
        /* Rx csum enabled and ip headers found? */
@@ -1287,6 +1314,7 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
        }
 
        skb->ip_summed = CHECKSUM_UNNECESSARY;
+       skb->csum_level = ipv4_tunnel || ipv6_tunnel;
 
        return;
 
@@ -2295,7 +2323,7 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,
                goto out_drop;
 
        /* obtain protocol of skb */
-       protocol = skb->protocol;
+       protocol = vlan_get_protocol(skb);
 
        /* record the location of the first descriptor for this packet */
        first = &tx_ring->tx_bi[tx_ring->next_to_use];
index 73f4fa4256974ed68479e5f6bebd44ee5d50d6bc..d7a625a6a14f54fa1b79456df9de7d14f9ff1809 100644 (file)
@@ -121,6 +121,7 @@ enum i40e_dyn_idx_t {
 /* Tx Descriptors needed, worst case */
 #define TXD_USE_COUNT(S) DIV_ROUND_UP((S), I40E_MAX_DATA_PER_TXD)
 #define DESC_NEEDED (MAX_SKB_FRAGS + 4)
+#define I40E_MIN_DESC_PENDING  4
 
 #define I40E_TX_FLAGS_CSUM             (u32)(1)
 #define I40E_TX_FLAGS_HW_VLAN          (u32)(1 << 1)
index 89672551dce93628e06d0d7777d25b55d51c8b27..4eeed267e4b71ce9d242d3a71fccd5ad38600c8f 100644 (file)
@@ -73,7 +73,7 @@ static inline bool i40e_vc_isvalid_queue_id(struct i40e_vf *vf, u8 vsi_id,
 {
        struct i40e_pf *pf = vf->pf;
 
-       return qid < pf->vsi[vsi_id]->num_queue_pairs;
+       return qid < pf->vsi[vsi_id]->alloc_queue_pairs;
 }
 
 /**
@@ -350,6 +350,7 @@ static int i40e_config_vsi_rx_queue(struct i40e_vf *vf, u16 vsi_idx,
        rx_ctx.lrxqthresh = 2;
        rx_ctx.crcstrip = 1;
        rx_ctx.prefena = 1;
+       rx_ctx.l2tsel = 1;
 
        /* clear the context in the HMC */
        ret = i40e_clear_lan_rx_queue_context(hw, pf_queue_id);
@@ -468,7 +469,7 @@ static void i40e_enable_vf_mappings(struct i40e_vf *vf)
        wr32(hw, I40E_VPLAN_MAPENA(vf->vf_id), reg);
 
        /* map PF queues to VF queues */
-       for (j = 0; j < pf->vsi[vf->lan_vsi_index]->num_queue_pairs; j++) {
+       for (j = 0; j < pf->vsi[vf->lan_vsi_index]->alloc_queue_pairs; j++) {
                u16 qid = i40e_vc_get_pf_queue_id(vf, vf->lan_vsi_index, j);
                reg = (qid & I40E_VPLAN_QTABLE_QINDEX_MASK);
                wr32(hw, I40E_VPLAN_QTABLE(total_queue_pairs, vf->vf_id), reg);
@@ -477,7 +478,7 @@ static void i40e_enable_vf_mappings(struct i40e_vf *vf)
 
        /* map PF queues to VSI */
        for (j = 0; j < 7; j++) {
-               if (j * 2 >= pf->vsi[vf->lan_vsi_index]->num_queue_pairs) {
+               if (j * 2 >= pf->vsi[vf->lan_vsi_index]->alloc_queue_pairs) {
                        reg = 0x07FF07FF;       /* unused */
                } else {
                        u16 qid = i40e_vc_get_pf_queue_id(vf, vf->lan_vsi_index,
@@ -584,7 +585,7 @@ static int i40e_alloc_vf_res(struct i40e_vf *vf)
        ret = i40e_alloc_vsi_res(vf, I40E_VSI_SRIOV);
        if (ret)
                goto error_alloc;
-       total_queue_pairs += pf->vsi[vf->lan_vsi_index]->num_queue_pairs;
+       total_queue_pairs += pf->vsi[vf->lan_vsi_index]->alloc_queue_pairs;
        set_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps);
 
        /* store the total qps number for the runtime
@@ -706,35 +707,6 @@ complete_reset:
        wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_id), I40E_VFR_VFACTIVE);
        i40e_flush(hw);
 }
-
-/**
- * i40e_vfs_are_assigned
- * @pf: pointer to the pf structure
- *
- * Determine if any VFs are assigned to VMs
- **/
-static bool i40e_vfs_are_assigned(struct i40e_pf *pf)
-{
-       struct pci_dev *pdev = pf->pdev;
-       struct pci_dev *vfdev;
-
-       /* loop through all the VFs to see if we own any that are assigned */
-       vfdev = pci_get_device(PCI_VENDOR_ID_INTEL, I40E_DEV_ID_VF , NULL);
-       while (vfdev) {
-               /* if we don't own it we don't care */
-               if (vfdev->is_virtfn && pci_physfn(vfdev) == pdev) {
-                       /* if it is assigned we cannot release it */
-                       if (vfdev->dev_flags & PCI_DEV_FLAGS_ASSIGNED)
-                               return true;
-               }
-
-               vfdev = pci_get_device(PCI_VENDOR_ID_INTEL,
-                                      I40E_DEV_ID_VF,
-                                      vfdev);
-       }
-
-       return false;
-}
 #ifdef CONFIG_PCI_IOV
 
 /**
@@ -842,7 +814,7 @@ void i40e_free_vfs(struct i40e_pf *pf)
         * assigned. Setting the number of VFs to 0 through sysfs is caught
         * before this function ever gets called.
         */
-       if (!i40e_vfs_are_assigned(pf)) {
+       if (!pci_vfs_assigned(pf->pdev)) {
                pci_disable_sriov(pf->pdev);
                /* Acknowledge VFLR for all VFS. Without this, VFs will fail to
                 * work correctly when SR-IOV gets re-enabled.
@@ -979,7 +951,7 @@ int i40e_pci_sriov_configure(struct pci_dev *pdev, int num_vfs)
        if (num_vfs)
                return i40e_pci_sriov_enable(pdev, num_vfs);
 
-       if (!i40e_vfs_are_assigned(pf)) {
+       if (!pci_vfs_assigned(pf->pdev)) {
                i40e_free_vfs(pf);
        } else {
                dev_warn(&pdev->dev, "Unable to free VFs because some are assigned to VMs.\n");
@@ -1003,11 +975,19 @@ int i40e_pci_sriov_configure(struct pci_dev *pdev, int num_vfs)
 static int i40e_vc_send_msg_to_vf(struct i40e_vf *vf, u32 v_opcode,
                                  u32 v_retval, u8 *msg, u16 msglen)
 {
-       struct i40e_pf *pf = vf->pf;
-       struct i40e_hw *hw = &pf->hw;
-       int abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id;
+       struct i40e_pf *pf;
+       struct i40e_hw *hw;
+       int abs_vf_id;
        i40e_status aq_ret;
 
+       /* validate the request */
+       if (!vf || vf->vf_id >= vf->pf->num_alloc_vfs)
+               return -EINVAL;
+
+       pf = vf->pf;
+       hw = &pf->hw;
+       abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id;
+
        /* single place to detect unsuccessful return values */
        if (v_retval) {
                vf->num_invalid_msgs++;
@@ -1115,7 +1095,7 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf)
                vfres->vsi_res[i].vsi_id = vf->lan_vsi_index;
                vfres->vsi_res[i].vsi_type = I40E_VSI_SRIOV;
                vfres->vsi_res[i].num_queue_pairs =
-                   pf->vsi[vf->lan_vsi_index]->num_queue_pairs;
+                   pf->vsi[vf->lan_vsi_index]->alloc_queue_pairs;
                memcpy(vfres->vsi_res[i].default_mac_addr,
                       vf->default_lan_addr.addr, ETH_ALEN);
                i++;
@@ -1201,6 +1181,7 @@ static int i40e_vc_config_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
        struct i40e_virtchnl_vsi_queue_config_info *qci =
            (struct i40e_virtchnl_vsi_queue_config_info *)msg;
        struct i40e_virtchnl_queue_pair_info *qpi;
+       struct i40e_pf *pf = vf->pf;
        u16 vsi_id, vsi_queue_id;
        i40e_status aq_ret = 0;
        int i;
@@ -1234,6 +1215,8 @@ static int i40e_vc_config_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
                        goto error_param;
                }
        }
+       /* set vsi num_queue_pairs in use to num configured by vf */
+       pf->vsi[vf->lan_vsi_index]->num_queue_pairs = qci->num_queue_pairs;
 
 error_param:
        /* send the response to the vf */
@@ -1928,17 +1911,20 @@ static void i40e_vc_vf_broadcast(struct i40e_pf *pf,
 {
        struct i40e_hw *hw = &pf->hw;
        struct i40e_vf *vf = pf->vf;
-       int abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id;
        int i;
 
-       for (i = 0; i < pf->num_alloc_vfs; i++) {
+       for (i = 0; i < pf->num_alloc_vfs; i++, vf++) {
+               int abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id;
+               /* Not all vfs are enabled so skip the ones that are not */
+               if (!test_bit(I40E_VF_STAT_INIT, &vf->vf_states) &&
+                   !test_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states))
+                       continue;
+
                /* Ignore return value on purpose - a given VF may fail, but
                 * we need to keep going and send to all of them
                 */
                i40e_aq_send_msg_to_vf(hw, abs_vf_id, v_opcode, v_retval,
                                       msg, msglen, NULL);
-               vf++;
-               abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id;
        }
 }
 
@@ -1954,12 +1940,12 @@ void i40e_vc_notify_link_state(struct i40e_pf *pf)
        struct i40e_hw *hw = &pf->hw;
        struct i40e_vf *vf = pf->vf;
        struct i40e_link_status *ls = &pf->hw.phy.link_info;
-       int abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id;
        int i;
 
        pfe.event = I40E_VIRTCHNL_EVENT_LINK_CHANGE;
        pfe.severity = I40E_PF_EVENT_SEVERITY_INFO;
-       for (i = 0; i < pf->num_alloc_vfs; i++) {
+       for (i = 0; i < pf->num_alloc_vfs; i++, vf++) {
+               int abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id;
                if (vf->link_forced) {
                        pfe.event_data.link_event.link_status = vf->link_up;
                        pfe.event_data.link_event.link_speed =
@@ -1972,8 +1958,6 @@ void i40e_vc_notify_link_state(struct i40e_pf *pf)
                i40e_aq_send_msg_to_vf(hw, abs_vf_id, I40E_VIRTCHNL_OP_EVENT,
                                       0, (u8 *)&pfe, sizeof(pfe),
                                       NULL);
-               vf++;
-               abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id;
        }
 }
 
@@ -2002,7 +1986,18 @@ void i40e_vc_notify_reset(struct i40e_pf *pf)
 void i40e_vc_notify_vf_reset(struct i40e_vf *vf)
 {
        struct i40e_virtchnl_pf_event pfe;
-       int abs_vf_id = vf->vf_id + vf->pf->hw.func_caps.vf_base_id;
+       int abs_vf_id;
+
+       /* validate the request */
+       if (!vf || vf->vf_id >= vf->pf->num_alloc_vfs)
+               return;
+
+       /* verify if the VF is in either init or active before proceeding */
+       if (!test_bit(I40E_VF_STAT_INIT, &vf->vf_states) &&
+           !test_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states))
+               return;
+
+       abs_vf_id = vf->vf_id + vf->pf->hw.func_caps.vf_base_id;
 
        pfe.event = I40E_VIRTCHNL_EVENT_RESET_IMPENDING;
        pfe.severity = I40E_PF_EVENT_SEVERITY_CERTAIN_DOOM;
@@ -2074,7 +2069,6 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
        /* Force the VF driver stop so it has to reload with new MAC address */
        i40e_vc_disable_vf(pf, vf);
        dev_info(&pf->pdev->dev, "Reload the VF driver to make this change effective.\n");
-       ret = 0;
 
 error_param:
        return ret;
@@ -2399,7 +2393,7 @@ error_out:
  *
  * Enable or disable VF spoof checking
  **/
-int i40e_ndo_set_vf_spoofck(struct net_device *netdev, int vf_id, bool enable)
+int i40e_ndo_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool enable)
 {
        struct i40e_netdev_priv *np = netdev_priv(netdev);
        struct i40e_vsi *vsi = np->vsi;
index 63e7e0d81ad22754622695dabc1a0475885477ee..0adc61e1052db9dabdcbea3d8930ec709e1868ef 100644 (file)
@@ -122,7 +122,7 @@ int i40e_ndo_set_vf_bw(struct net_device *netdev, int vf_id, int min_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);
-int i40e_ndo_set_vf_spoofck(struct net_device *netdev, int vf_id, bool enable);
+int i40e_ndo_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool enable);
 
 void i40e_vc_notify_link_state(struct i40e_pf *pf);
 void i40e_vc_notify_reset(struct i40e_pf *pf);
index 00300603361464b4e9f3b20da7774a1069bdf071..f206be9178422afc01a955f481f8e523cbb3093c 100644 (file)
@@ -788,7 +788,8 @@ i40e_status i40evf_asq_send_command(struct i40e_hw *hw,
 
        /* bump the tail */
        i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: desc and buffer:\n");
-       i40evf_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc_on_ring, buff);
+       i40evf_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc_on_ring,
+                       buff, buff_size);
        (hw->aq.asq.next_to_use)++;
        if (hw->aq.asq.next_to_use == hw->aq.asq.count)
                hw->aq.asq.next_to_use = 0;
@@ -842,7 +843,8 @@ i40e_status i40evf_asq_send_command(struct i40e_hw *hw,
 
        i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE,
                   "AQTX: desc and buffer writeback:\n");
-       i40evf_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, buff);
+       i40evf_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, buff,
+                       buff_size);
 
        /* update the error if time out occurred */
        if ((!cmd_completed) &&
@@ -938,7 +940,8 @@ i40e_status i40evf_clean_arq_element(struct i40e_hw *hw,
                hw->aq.nvm_busy = false;
 
        i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQRX: desc and buffer:\n");
-       i40evf_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, e->msg_buf);
+       i40evf_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc, e->msg_buf,
+                       hw->aq.arq_buf_size);
 
        /* Restore the original datalen and buffer address in the desc,
         * FW updates datalen to indicate the event message
index 4ea90bf239bb204ed5603b66680413191f46bf66..9525605519645eb241f5473bcdd345a0afe21a09 100644 (file)
@@ -75,13 +75,15 @@ i40e_status i40e_set_mac_type(struct i40e_hw *hw)
  * @mask: debug mask
  * @desc: pointer to admin queue descriptor
  * @buffer: pointer to command buffer
+ * @buf_len: max length of buffer
  *
  * Dumps debug log about adminq command with descriptor contents.
  **/
 void i40evf_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask, void *desc,
-                  void *buffer)
+                  void *buffer, u16 buf_len)
 {
        struct i40e_aq_desc *aq_desc = (struct i40e_aq_desc *)desc;
+       u16 len = le16_to_cpu(aq_desc->datalen);
        u8 *aq_buffer = (u8 *)buffer;
        u32 data[4];
        u32 i = 0;
@@ -105,7 +107,9 @@ void i40evf_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask, void *desc,
        if ((buffer != NULL) && (aq_desc->datalen != 0)) {
                memset(data, 0, sizeof(data));
                i40e_debug(hw, mask, "AQ CMD Buffer:\n");
-               for (i = 0; i < le16_to_cpu(aq_desc->datalen); i++) {
+               if (buf_len < len)
+                       len = buf_len;
+               for (i = 0; i < len; i++) {
                        data[((i % 16) / 4)] |=
                                ((u32)aq_buffer[i]) << (8 * (i % 4));
                        if ((i % 16) == 15) {
index 849edcc2e398f7bfdaaea5eaf078ba714977ca5f..9173834825ac4cc1bbe5c3ecbc85e77db693c76f 100644 (file)
@@ -53,10 +53,8 @@ i40e_status i40evf_asq_send_command(struct i40e_hw *hw,
 bool i40evf_asq_done(struct i40e_hw *hw);
 
 /* debug function for adminq */
-void i40evf_debug_aq(struct i40e_hw *hw,
-                  enum i40e_debug_mask mask,
-                  void *desc,
-                  void *buffer);
+void i40evf_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask,
+                    void *desc, void *buffer, u16 buf_len);
 
 void i40e_idle_aq(struct i40e_hw *hw);
 void i40evf_resume_aq(struct i40e_hw *hw);
index 79bf96ca648954b390dbf60728ae687181292097..04c7c1557a0c770ab0f256d3012cd3b9be70240e 100644 (file)
@@ -163,11 +163,13 @@ static bool i40e_check_tx_hang(struct i40e_ring *tx_ring)
         * pending but without time to complete it yet.
         */
        if ((tx_ring->tx_stats.tx_done_old == tx_ring->stats.packets) &&
-           tx_pending) {
+           (tx_pending >= I40E_MIN_DESC_PENDING)) {
                /* make sure it is true for two checks in a row */
                ret = test_and_set_bit(__I40E_HANG_CHECK_ARMED,
                                       &tx_ring->state);
-       } else {
+       } else if (!(tx_ring->tx_stats.tx_done_old == tx_ring->stats.packets) ||
+                  !(tx_pending < I40E_MIN_DESC_PENDING) ||
+                  !(tx_pending > 0)) {
                /* update completed stats and disarm the hang check */
                tx_ring->tx_stats.tx_done_old = tx_ring->stats.packets;
                clear_bit(__I40E_HANG_CHECK_ARMED, &tx_ring->state);
@@ -744,7 +746,6 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
        ipv6_tunnel = (rx_ptype > I40E_RX_PTYPE_GRENAT6_MAC_PAY3) &&
                      (rx_ptype < I40E_RX_PTYPE_GRENAT6_MACVLAN_IPV6_ICMP_PAY4);
 
-       skb->encapsulation = ipv4_tunnel || ipv6_tunnel;
        skb->ip_summed = CHECKSUM_NONE;
 
        /* Rx csum enabled and ip headers found? */
@@ -818,6 +819,7 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
        }
 
        skb->ip_summed = CHECKSUM_UNNECESSARY;
+       skb->csum_level = ipv4_tunnel || ipv6_tunnel;
 
        return;
 
@@ -1597,7 +1599,7 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,
                goto out_drop;
 
        /* obtain protocol of skb */
-       protocol = skb->protocol;
+       protocol = vlan_get_protocol(skb);
 
        /* record the location of the first descriptor for this packet */
        first = &tx_ring->tx_bi[tx_ring->next_to_use];
index 8bc6858163b0f1b668e56d3c0d682574cc4582d5..f6dcf9dd9290d95554c7505f4bbd9f5832185597 100644 (file)
@@ -121,6 +121,7 @@ enum i40e_dyn_idx_t {
 /* Tx Descriptors needed, worst case */
 #define TXD_USE_COUNT(S) DIV_ROUND_UP((S), I40E_MAX_DATA_PER_TXD)
 #define DESC_NEEDED (MAX_SKB_FRAGS + 4)
+#define I40E_MIN_DESC_PENDING  4
 
 #define I40E_TX_FLAGS_CSUM             (u32)(1)
 #define I40E_TX_FLAGS_HW_VLAN          (u32)(1 << 1)
index 38429fae4fcfa2ccb1db770e7e735e27303b8c2d..c51bc7a33bc50898dedf7f1fdfaa5100c45e501a 100644 (file)
@@ -36,7 +36,7 @@ char i40evf_driver_name[] = "i40evf";
 static const char i40evf_driver_string[] =
        "Intel(R) XL710/X710 Virtual Function Network Driver";
 
-#define DRV_VERSION "0.9.40"
+#define DRV_VERSION "1.0.5"
 const char i40evf_driver_version[] = DRV_VERSION;
 static const char i40evf_copyright[] =
        "Copyright (c) 2013 - 2014 Intel Corporation.";
index 236a6183a86523a3aef0430b3a575081b32ba7b5..051ea94bdcd3e8046181b361d8985c51d15ea19c 100644 (file)
@@ -2548,11 +2548,13 @@ s32 igb_read_emi_reg(struct e1000_hw *hw, u16 addr, u16 *data)
 /**
  *  igb_set_eee_i350 - Enable/disable EEE support
  *  @hw: pointer to the HW structure
+ *  @adv1G: boolean flag enabling 1G EEE advertisement
+ *  @adv100m: boolean flag enabling 100M EEE advertisement
  *
  *  Enable/disable EEE based on setting in dev_spec structure.
  *
  **/
-s32 igb_set_eee_i350(struct e1000_hw *hw)
+s32 igb_set_eee_i350(struct e1000_hw *hw, bool adv1G, bool adv100M)
 {
        u32 ipcnfg, eeer;
 
@@ -2566,7 +2568,16 @@ s32 igb_set_eee_i350(struct e1000_hw *hw)
        if (!(hw->dev_spec._82575.eee_disable)) {
                u32 eee_su = rd32(E1000_EEE_SU);
 
-               ipcnfg |= (E1000_IPCNFG_EEE_1G_AN | E1000_IPCNFG_EEE_100M_AN);
+               if (adv100M)
+                       ipcnfg |= E1000_IPCNFG_EEE_100M_AN;
+               else
+                       ipcnfg &= ~E1000_IPCNFG_EEE_100M_AN;
+
+               if (adv1G)
+                       ipcnfg |= E1000_IPCNFG_EEE_1G_AN;
+               else
+                       ipcnfg &= ~E1000_IPCNFG_EEE_1G_AN;
+
                eeer |= (E1000_EEER_TX_LPI_EN | E1000_EEER_RX_LPI_EN |
                        E1000_EEER_LPI_FC);
 
@@ -2593,11 +2604,13 @@ out:
 /**
  *  igb_set_eee_i354 - Enable/disable EEE support
  *  @hw: pointer to the HW structure
+ *  @adv1G: boolean flag enabling 1G EEE advertisement
+ *  @adv100m: boolean flag enabling 100M EEE advertisement
  *
  *  Enable/disable EEE legacy mode based on setting in dev_spec structure.
  *
  **/
-s32 igb_set_eee_i354(struct e1000_hw *hw)
+s32 igb_set_eee_i354(struct e1000_hw *hw, bool adv1G, bool adv100M)
 {
        struct e1000_phy_info *phy = &hw->phy;
        s32 ret_val = 0;
@@ -2636,8 +2649,16 @@ s32 igb_set_eee_i354(struct e1000_hw *hw)
                if (ret_val)
                        goto out;
 
-               phy_data |= E1000_EEE_ADV_100_SUPPORTED |
-                           E1000_EEE_ADV_1000_SUPPORTED;
+               if (adv100M)
+                       phy_data |= E1000_EEE_ADV_100_SUPPORTED;
+               else
+                       phy_data &= ~E1000_EEE_ADV_100_SUPPORTED;
+
+               if (adv1G)
+                       phy_data |= E1000_EEE_ADV_1000_SUPPORTED;
+               else
+                       phy_data &= ~E1000_EEE_ADV_1000_SUPPORTED;
+
                ret_val = igb_write_xmdio_reg(hw, E1000_EEE_ADV_ADDR_I354,
                                                E1000_EEE_ADV_DEV_I354,
                                                phy_data);
index b407c55738fadf0a333ee7947fedd2c0c31638a1..2154aea7aa7e70c9d5083bc3631a37f885d48bd4 100644 (file)
@@ -263,8 +263,8 @@ void igb_vmdq_set_loopback_pf(struct e1000_hw *, bool);
 void igb_vmdq_set_replication_pf(struct e1000_hw *, bool);
 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_set_eee_i350(struct e1000_hw *, bool adv1G, bool adv100M);
+s32 igb_set_eee_i354(struct e1000_hw *, bool adv1G, bool adv100M);
 s32 igb_get_eee_status_i354(struct e1000_hw *hw, bool *status);
 
 #define E1000_I2C_THERMAL_SENSOR_ADDR  0xF8
index c737d1f4083829ae0eed6e7ecff1d29b5c75239e..02cfd3b14762cbf884ef1b0f4586735f14bee3c9 100644 (file)
@@ -2675,6 +2675,7 @@ static int igb_set_eee(struct net_device *netdev,
        struct igb_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
        struct ethtool_eee eee_curr;
+       bool adv1g_eee = true, adv100m_eee = true;
        s32 ret_val;
 
        if ((hw->mac.type < e1000_i350) ||
@@ -2701,12 +2702,14 @@ static int igb_set_eee(struct net_device *netdev,
                        return -EINVAL;
                }
 
-               if (edata->advertised &
-                   ~(ADVERTISE_100_FULL | ADVERTISE_1000_FULL)) {
+               if (!edata->advertised || (edata->advertised &
+                   ~(ADVERTISE_100_FULL | ADVERTISE_1000_FULL))) {
                        dev_err(&adapter->pdev->dev,
-                               "EEE Advertisement supports only 100Tx and or 100T full duplex\n");
+                               "EEE Advertisement supports only 100Tx and/or 100T full duplex\n");
                        return -EINVAL;
                }
+               adv100m_eee = !!(edata->advertised & ADVERTISE_100_FULL);
+               adv1g_eee = !!(edata->advertised & ADVERTISE_1000_FULL);
 
        } else if (!edata->eee_enabled) {
                dev_err(&adapter->pdev->dev,
@@ -2718,10 +2721,6 @@ static int igb_set_eee(struct net_device *netdev,
        if (hw->dev_spec._82575.eee_disable != !edata->eee_enabled) {
                hw->dev_spec._82575.eee_disable = !edata->eee_enabled;
                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))
@@ -2730,6 +2729,17 @@ static int igb_set_eee(struct net_device *netdev,
                        igb_reset(adapter);
        }
 
+       if (hw->mac.type == e1000_i354)
+               ret_val = igb_set_eee_i354(hw, adv1g_eee, adv100m_eee);
+       else
+               ret_val = igb_set_eee_i350(hw, adv1g_eee, adv100m_eee);
+
+       if (ret_val) {
+               dev_err(&adapter->pdev->dev,
+                       "Problem setting EEE advertisement options\n");
+               return -EINVAL;
+       }
+
        return 0;
 }
 
index cb14bbdfb0562df213253d18c83eaf78c6a63f2c..6cf0c17ad9c4abe03f5eb4e1b9ef474aefdc76d2 100644 (file)
@@ -2012,10 +2012,10 @@ void igb_reset(struct igb_adapter *adapter)
                case e1000_i350:
                case e1000_i210:
                case e1000_i211:
-                       igb_set_eee_i350(hw);
+                       igb_set_eee_i350(hw, true, true);
                        break;
                case e1000_i354:
-                       igb_set_eee_i354(hw);
+                       igb_set_eee_i354(hw, true, true);
                        break;
                default:
                        break;
@@ -2619,7 +2619,7 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                case e1000_i210:
                case e1000_i211:
                        /* Enable EEE for internal copper PHY devices */
-                       err = igb_set_eee_i350(hw);
+                       err = igb_set_eee_i350(hw, true, true);
                        if ((!err) &&
                            (!hw->dev_spec._82575.eee_disable)) {
                                adapter->eee_advert =
@@ -2630,7 +2630,7 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                case e1000_i354:
                        if ((rd32(E1000_CTRL_EXT) &
                            E1000_CTRL_EXT_LINK_MODE_SGMII)) {
-                               err = igb_set_eee_i354(hw);
+                               err = igb_set_eee_i354(hw, true, true);
                                if ((!err) &&
                                        (!hw->dev_spec._82575.eee_disable)) {
                                        adapter->eee_advert =
@@ -4813,6 +4813,41 @@ static void igb_tx_olinfo_status(struct igb_ring *tx_ring,
        tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status);
 }
 
+static int __igb_maybe_stop_tx(struct igb_ring *tx_ring, const u16 size)
+{
+       struct net_device *netdev = tx_ring->netdev;
+
+       netif_stop_subqueue(netdev, tx_ring->queue_index);
+
+       /* Herbert's original patch had:
+        *  smp_mb__after_netif_stop_queue();
+        * but since that doesn't exist yet, just open code it.
+        */
+       smp_mb();
+
+       /* We need to check again in a case another CPU has just
+        * made room available.
+        */
+       if (igb_desc_unused(tx_ring) < size)
+               return -EBUSY;
+
+       /* A reprieve! */
+       netif_wake_subqueue(netdev, tx_ring->queue_index);
+
+       u64_stats_update_begin(&tx_ring->tx_syncp2);
+       tx_ring->tx_stats.restart_queue2++;
+       u64_stats_update_end(&tx_ring->tx_syncp2);
+
+       return 0;
+}
+
+static inline int igb_maybe_stop_tx(struct igb_ring *tx_ring, const u16 size)
+{
+       if (igb_desc_unused(tx_ring) >= size)
+               return 0;
+       return __igb_maybe_stop_tx(tx_ring, size);
+}
+
 static void igb_tx_map(struct igb_ring *tx_ring,
                       struct igb_tx_buffer *first,
                       const u8 hdr_len)
@@ -4915,13 +4950,17 @@ static void igb_tx_map(struct igb_ring *tx_ring,
 
        tx_ring->next_to_use = i;
 
-       writel(i, tx_ring->tail);
+       /* Make sure there is space in the ring for the next send. */
+       igb_maybe_stop_tx(tx_ring, DESC_NEEDED);
 
-       /* we need this if more than one processor can write to our tail
-        * at a time, it synchronizes IO on IA64/Altix systems
-        */
-       mmiowb();
+       if (netif_xmit_stopped(txring_txq(tx_ring)) || !skb->xmit_more) {
+               writel(i, tx_ring->tail);
 
+               /* we need this if more than one processor can write to our tail
+                * at a time, it synchronizes IO on IA64/Altix systems
+                */
+               mmiowb();
+       }
        return;
 
 dma_error:
@@ -4941,41 +4980,6 @@ dma_error:
        tx_ring->next_to_use = i;
 }
 
-static int __igb_maybe_stop_tx(struct igb_ring *tx_ring, const u16 size)
-{
-       struct net_device *netdev = tx_ring->netdev;
-
-       netif_stop_subqueue(netdev, tx_ring->queue_index);
-
-       /* Herbert's original patch had:
-        *  smp_mb__after_netif_stop_queue();
-        * but since that doesn't exist yet, just open code it.
-        */
-       smp_mb();
-
-       /* We need to check again in a case another CPU has just
-        * made room available.
-        */
-       if (igb_desc_unused(tx_ring) < size)
-               return -EBUSY;
-
-       /* A reprieve! */
-       netif_wake_subqueue(netdev, tx_ring->queue_index);
-
-       u64_stats_update_begin(&tx_ring->tx_syncp2);
-       tx_ring->tx_stats.restart_queue2++;
-       u64_stats_update_end(&tx_ring->tx_syncp2);
-
-       return 0;
-}
-
-static inline int igb_maybe_stop_tx(struct igb_ring *tx_ring, const u16 size)
-{
-       if (igb_desc_unused(tx_ring) >= size)
-               return 0;
-       return __igb_maybe_stop_tx(tx_ring, size);
-}
-
 netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb,
                                struct igb_ring *tx_ring)
 {
@@ -5046,9 +5050,6 @@ netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb,
 
        igb_tx_map(tx_ring, first, hdr_len);
 
-       /* Make sure there is space in the ring for the next send. */
-       igb_maybe_stop_tx(tx_ring, DESC_NEEDED);
-
        return NETDEV_TX_OK;
 
 out_drop:
@@ -6767,113 +6768,6 @@ static bool igb_is_non_eop(struct igb_ring *rx_ring,
        return true;
 }
 
-/**
- *  igb_get_headlen - determine size of header for LRO/GRO
- *  @data: pointer to the start of the headers
- *  @max_len: total length of section to find headers in
- *
- *  This function is meant to determine the length of headers that will
- *  be recognized by hardware for LRO, and GRO offloads.  The main
- *  motivation of doing this is to only perform one pull for IPv4 TCP
- *  packets so that we can do basic things like calculating the gso_size
- *  based on the average data per packet.
- **/
-static unsigned int igb_get_headlen(unsigned char *data,
-                                   unsigned int max_len)
-{
-       union {
-               unsigned char *network;
-               /* l2 headers */
-               struct ethhdr *eth;
-               struct vlan_hdr *vlan;
-               /* l3 headers */
-               struct iphdr *ipv4;
-               struct ipv6hdr *ipv6;
-       } hdr;
-       __be16 protocol;
-       u8 nexthdr = 0; /* default to not TCP */
-       u8 hlen;
-
-       /* this should never happen, but better safe than sorry */
-       if (max_len < ETH_HLEN)
-               return max_len;
-
-       /* initialize network frame pointer */
-       hdr.network = data;
-
-       /* set first protocol and move network header forward */
-       protocol = hdr.eth->h_proto;
-       hdr.network += ETH_HLEN;
-
-       /* handle any vlan tag if present */
-       if (protocol == htons(ETH_P_8021Q)) {
-               if ((hdr.network - data) > (max_len - VLAN_HLEN))
-                       return max_len;
-
-               protocol = hdr.vlan->h_vlan_encapsulated_proto;
-               hdr.network += VLAN_HLEN;
-       }
-
-       /* handle L3 protocols */
-       if (protocol == htons(ETH_P_IP)) {
-               if ((hdr.network - data) > (max_len - sizeof(struct iphdr)))
-                       return max_len;
-
-               /* access ihl as a u8 to avoid unaligned access on ia64 */
-               hlen = (hdr.network[0] & 0x0F) << 2;
-
-               /* verify hlen meets minimum size requirements */
-               if (hlen < sizeof(struct iphdr))
-                       return hdr.network - data;
-
-               /* record next protocol if header is present */
-               if (!(hdr.ipv4->frag_off & htons(IP_OFFSET)))
-                       nexthdr = hdr.ipv4->protocol;
-       } else if (protocol == htons(ETH_P_IPV6)) {
-               if ((hdr.network - data) > (max_len - sizeof(struct ipv6hdr)))
-                       return max_len;
-
-               /* record next protocol */
-               nexthdr = hdr.ipv6->nexthdr;
-               hlen = sizeof(struct ipv6hdr);
-       } else {
-               return hdr.network - data;
-       }
-
-       /* relocate pointer to start of L4 header */
-       hdr.network += hlen;
-
-       /* finally sort out TCP */
-       if (nexthdr == IPPROTO_TCP) {
-               if ((hdr.network - data) > (max_len - sizeof(struct tcphdr)))
-                       return max_len;
-
-               /* access doff as a u8 to avoid unaligned access on ia64 */
-               hlen = (hdr.network[12] & 0xF0) >> 2;
-
-               /* verify hlen meets minimum size requirements */
-               if (hlen < sizeof(struct tcphdr))
-                       return hdr.network - data;
-
-               hdr.network += hlen;
-       } else if (nexthdr == IPPROTO_UDP) {
-               if ((hdr.network - data) > (max_len - sizeof(struct udphdr)))
-                       return max_len;
-
-               hdr.network += sizeof(struct udphdr);
-       }
-
-       /* If everything has gone correctly hdr.network should be the
-        * data section of the packet and will be the end of the header.
-        * If not then it probably represents the end of the last recognized
-        * header.
-        */
-       if ((hdr.network - data) < max_len)
-               return hdr.network - data;
-       else
-               return max_len;
-}
-
 /**
  *  igb_pull_tail - igb specific version of skb_pull_tail
  *  @rx_ring: rx descriptor ring packet is being transacted on
@@ -6918,7 +6812,7 @@ static void igb_pull_tail(struct igb_ring *rx_ring,
        /* we need the header to contain the greater of either ETH_HLEN or
         * 60 bytes if the skb->len is less than 60 for skb_pad.
         */
-       pull_len = igb_get_headlen(va, IGB_RX_HDR_LEN);
+       pull_len = eth_get_headlen(va, IGB_RX_HDR_LEN);
 
        /* align pull length to size of long to optimize memcpy performance */
        skb_copy_to_linear_data(skb, va, ALIGN(pull_len, sizeof(long)));
index 2d9451e3968624db0b527dd00e9a106adfae16be..ae36fd61a3aa93374e603206dcf77a3f287a2984 100644 (file)
@@ -1086,6 +1086,11 @@ static void ixgbe_set_interrupt_capability(struct ixgbe_adapter *adapter)
                        return;
        }
 
+       /* At this point, we do not have MSI-X capabilities. We need to
+        * reconfigure or disable various features which require MSI-X
+        * capability.
+        */
+
        /* disable DCB if number of TCs exceeds 1 */
        if (netdev_get_num_tc(adapter->netdev) > 1) {
                e_err(probe, "num TCs exceeds number of queues - disabling DCB\n");
@@ -1107,6 +1112,9 @@ static void ixgbe_set_interrupt_capability(struct ixgbe_adapter *adapter)
        /* disable RSS */
        adapter->ring_feature[RING_F_RSS].limit = 1;
 
+       /* recalculate number of queues now that many features have been
+        * changed or disabled.
+        */
        ixgbe_set_num_queues(adapter);
        adapter->num_q_vectors = 1;
 
index 87bd53fdd209152dc14a09fbee8101582237c6e8..166dc0015a5e91b21ff2d03ac8cf7764732ecbdd 100644 (file)
@@ -1521,120 +1521,6 @@ void ixgbe_alloc_rx_buffers(struct ixgbe_ring *rx_ring, u16 cleaned_count)
                ixgbe_release_rx_desc(rx_ring, i);
 }
 
-/**
- * ixgbe_get_headlen - determine size of header for RSC/LRO/GRO/FCOE
- * @data: pointer to the start of the headers
- * @max_len: total length of section to find headers in
- *
- * This function is meant to determine the length of headers that will
- * be recognized by hardware for LRO, GRO, and RSC offloads.  The main
- * motivation of doing this is to only perform one pull for IPv4 TCP
- * packets so that we can do basic things like calculating the gso_size
- * based on the average data per packet.
- **/
-static unsigned int ixgbe_get_headlen(unsigned char *data,
-                                     unsigned int max_len)
-{
-       union {
-               unsigned char *network;
-               /* l2 headers */
-               struct ethhdr *eth;
-               struct vlan_hdr *vlan;
-               /* l3 headers */
-               struct iphdr *ipv4;
-               struct ipv6hdr *ipv6;
-       } hdr;
-       __be16 protocol;
-       u8 nexthdr = 0; /* default to not TCP */
-       u8 hlen;
-
-       /* this should never happen, but better safe than sorry */
-       if (max_len < ETH_HLEN)
-               return max_len;
-
-       /* initialize network frame pointer */
-       hdr.network = data;
-
-       /* set first protocol and move network header forward */
-       protocol = hdr.eth->h_proto;
-       hdr.network += ETH_HLEN;
-
-       /* handle any vlan tag if present */
-       if (protocol == htons(ETH_P_8021Q)) {
-               if ((hdr.network - data) > (max_len - VLAN_HLEN))
-                       return max_len;
-
-               protocol = hdr.vlan->h_vlan_encapsulated_proto;
-               hdr.network += VLAN_HLEN;
-       }
-
-       /* handle L3 protocols */
-       if (protocol == htons(ETH_P_IP)) {
-               if ((hdr.network - data) > (max_len - sizeof(struct iphdr)))
-                       return max_len;
-
-               /* access ihl as a u8 to avoid unaligned access on ia64 */
-               hlen = (hdr.network[0] & 0x0F) << 2;
-
-               /* verify hlen meets minimum size requirements */
-               if (hlen < sizeof(struct iphdr))
-                       return hdr.network - data;
-
-               /* record next protocol if header is present */
-               if (!(hdr.ipv4->frag_off & htons(IP_OFFSET)))
-                       nexthdr = hdr.ipv4->protocol;
-       } else if (protocol == htons(ETH_P_IPV6)) {
-               if ((hdr.network - data) > (max_len - sizeof(struct ipv6hdr)))
-                       return max_len;
-
-               /* record next protocol */
-               nexthdr = hdr.ipv6->nexthdr;
-               hlen = sizeof(struct ipv6hdr);
-#ifdef IXGBE_FCOE
-       } else if (protocol == htons(ETH_P_FCOE)) {
-               if ((hdr.network - data) > (max_len - FCOE_HEADER_LEN))
-                       return max_len;
-               hlen = FCOE_HEADER_LEN;
-#endif
-       } else {
-               return hdr.network - data;
-       }
-
-       /* relocate pointer to start of L4 header */
-       hdr.network += hlen;
-
-       /* finally sort out TCP/UDP */
-       if (nexthdr == IPPROTO_TCP) {
-               if ((hdr.network - data) > (max_len - sizeof(struct tcphdr)))
-                       return max_len;
-
-               /* access doff as a u8 to avoid unaligned access on ia64 */
-               hlen = (hdr.network[12] & 0xF0) >> 2;
-
-               /* verify hlen meets minimum size requirements */
-               if (hlen < sizeof(struct tcphdr))
-                       return hdr.network - data;
-
-               hdr.network += hlen;
-       } else if (nexthdr == IPPROTO_UDP) {
-               if ((hdr.network - data) > (max_len - sizeof(struct udphdr)))
-                       return max_len;
-
-               hdr.network += sizeof(struct udphdr);
-       }
-
-       /*
-        * If everything has gone correctly hdr.network should be the
-        * data section of the packet and will be the end of the header.
-        * If not then it probably represents the end of the last recognized
-        * header.
-        */
-       if ((hdr.network - data) < max_len)
-               return hdr.network - data;
-       else
-               return max_len;
-}
-
 static void ixgbe_set_rsc_gso_size(struct ixgbe_ring *ring,
                                   struct sk_buff *skb)
 {
@@ -1793,7 +1679,7 @@ static void ixgbe_pull_tail(struct ixgbe_ring *rx_ring,
         * we need the header to contain the greater of either ETH_HLEN or
         * 60 bytes if the skb->len is less than 60 for skb_pad.
         */
-       pull_len = ixgbe_get_headlen(va, IXGBE_RX_HDR_SIZE);
+       pull_len = eth_get_headlen(va, IXGBE_RX_HDR_SIZE);
 
        /* align pull length to size of long to optimize memcpy performance */
        skb_copy_to_linear_data(skb, va, ALIGN(pull_len, sizeof(long)));
@@ -6319,25 +6205,55 @@ static void ixgbe_watchdog_link_is_down(struct ixgbe_adapter *adapter)
        ixgbe_ping_all_vfs(adapter);
 }
 
+static bool ixgbe_ring_tx_pending(struct ixgbe_adapter *adapter)
+{
+       int i;
+
+       for (i = 0; i < adapter->num_tx_queues; i++) {
+               struct ixgbe_ring *tx_ring = adapter->tx_ring[i];
+
+               if (tx_ring->next_to_use != tx_ring->next_to_clean)
+                       return true;
+       }
+
+       return false;
+}
+
+static bool ixgbe_vf_tx_pending(struct ixgbe_adapter *adapter)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       struct ixgbe_ring_feature *vmdq = &adapter->ring_feature[RING_F_VMDQ];
+       u32 q_per_pool = __ALIGN_MASK(1, ~vmdq->mask);
+
+       int i, j;
+
+       if (!adapter->num_vfs)
+               return false;
+
+       for (i = 0; i < adapter->num_vfs; i++) {
+               for (j = 0; j < q_per_pool; j++) {
+                       u32 h, t;
+
+                       h = IXGBE_READ_REG(hw, IXGBE_PVFTDHN(q_per_pool, i, j));
+                       t = IXGBE_READ_REG(hw, IXGBE_PVFTDTN(q_per_pool, i, j));
+
+                       if (h != t)
+                               return true;
+               }
+       }
+
+       return false;
+}
+
 /**
  * ixgbe_watchdog_flush_tx - flush queues on link down
  * @adapter: pointer to the device adapter structure
  **/
 static void ixgbe_watchdog_flush_tx(struct ixgbe_adapter *adapter)
 {
-       int i;
-       int some_tx_pending = 0;
-
        if (!netif_carrier_ok(adapter->netdev)) {
-               for (i = 0; i < adapter->num_tx_queues; i++) {
-                       struct ixgbe_ring *tx_ring = adapter->tx_ring[i];
-                       if (tx_ring->next_to_use != tx_ring->next_to_clean) {
-                               some_tx_pending = 1;
-                               break;
-                       }
-               }
-
-               if (some_tx_pending) {
+               if (ixgbe_ring_tx_pending(adapter) ||
+                   ixgbe_vf_tx_pending(adapter)) {
                        /* We've lost link, so the controller stops DMA,
                         * but we've got queued Tx work that's never going
                         * to get done, so reset controller to flush Tx.
@@ -6837,6 +6753,36 @@ static void ixgbe_tx_olinfo_status(union ixgbe_adv_tx_desc *tx_desc,
        tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status);
 }
 
+static int __ixgbe_maybe_stop_tx(struct ixgbe_ring *tx_ring, u16 size)
+{
+       netif_stop_subqueue(tx_ring->netdev, tx_ring->queue_index);
+
+       /* Herbert's original patch had:
+        *  smp_mb__after_netif_stop_queue();
+        * but since that doesn't exist yet, just open code it.
+        */
+       smp_mb();
+
+       /* We need to check again in a case another CPU has just
+        * made room available.
+        */
+       if (likely(ixgbe_desc_unused(tx_ring) < size))
+               return -EBUSY;
+
+       /* A reprieve! - use start_queue because it doesn't call schedule */
+       netif_start_subqueue(tx_ring->netdev, tx_ring->queue_index);
+       ++tx_ring->tx_stats.restart_queue;
+       return 0;
+}
+
+static inline int ixgbe_maybe_stop_tx(struct ixgbe_ring *tx_ring, u16 size)
+{
+       if (likely(ixgbe_desc_unused(tx_ring) >= size))
+               return 0;
+
+       return __ixgbe_maybe_stop_tx(tx_ring, size);
+}
+
 #define IXGBE_TXD_CMD (IXGBE_TXD_CMD_EOP | \
                       IXGBE_TXD_CMD_RS)
 
@@ -6958,8 +6904,12 @@ static void ixgbe_tx_map(struct ixgbe_ring *tx_ring,
 
        tx_ring->next_to_use = i;
 
-       /* notify HW of packet */
-       ixgbe_write_tail(tx_ring, i);
+       ixgbe_maybe_stop_tx(tx_ring, DESC_NEEDED);
+
+       if (netif_xmit_stopped(txring_txq(tx_ring)) || !skb->xmit_more) {
+               /* notify HW of packet */
+               ixgbe_write_tail(tx_ring, i);
+       }
 
        return;
 dma_error:
@@ -7067,32 +7017,6 @@ static void ixgbe_atr(struct ixgbe_ring *ring,
                                              input, common, ring->queue_index);
 }
 
-static int __ixgbe_maybe_stop_tx(struct ixgbe_ring *tx_ring, u16 size)
-{
-       netif_stop_subqueue(tx_ring->netdev, tx_ring->queue_index);
-       /* Herbert's original patch had:
-        *  smp_mb__after_netif_stop_queue();
-        * but since that doesn't exist yet, just open code it. */
-       smp_mb();
-
-       /* We need to check again in a case another CPU has just
-        * made room available. */
-       if (likely(ixgbe_desc_unused(tx_ring) < size))
-               return -EBUSY;
-
-       /* A reprieve! - use start_queue because it doesn't call schedule */
-       netif_start_subqueue(tx_ring->netdev, tx_ring->queue_index);
-       ++tx_ring->tx_stats.restart_queue;
-       return 0;
-}
-
-static inline int ixgbe_maybe_stop_tx(struct ixgbe_ring *tx_ring, u16 size)
-{
-       if (likely(ixgbe_desc_unused(tx_ring) >= size))
-               return 0;
-       return __ixgbe_maybe_stop_tx(tx_ring, size);
-}
-
 static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb,
                              void *accel_priv, select_queue_fallback_t fallback)
 {
@@ -7261,8 +7185,6 @@ xmit_fcoe:
 #endif /* IXGBE_FCOE */
        ixgbe_tx_map(tx_ring, first, hdr_len);
 
-       ixgbe_maybe_stop_tx(tx_ring, DESC_NEEDED);
-
        return NETDEV_TX_OK;
 
 out_drop:
@@ -7735,39 +7657,13 @@ static int ixgbe_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
                             const unsigned char *addr,
                             u16 flags)
 {
-       struct ixgbe_adapter *adapter = netdev_priv(dev);
-       int err;
-
-       if (!(adapter->flags & IXGBE_FLAG_SRIOV_ENABLED))
-               return ndo_dflt_fdb_add(ndm, tb, dev, addr, flags);
-
-       /* Hardware does not support aging addresses so if a
-        * ndm_state is given only allow permanent addresses
-        */
-       if (ndm->ndm_state && !(ndm->ndm_state & NUD_PERMANENT)) {
-               pr_info("%s: FDB only supports static addresses\n",
-                       ixgbe_driver_name);
-               return -EINVAL;
-       }
-
+       /* guarantee we can provide a unique filter for the unicast address */
        if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr)) {
-               u32 rar_uc_entries = IXGBE_MAX_PF_MACVLANS;
-
-               if (netdev_uc_count(dev) < rar_uc_entries)
-                       err = dev_uc_add_excl(dev, addr);
-               else
-                       err = -ENOMEM;
-       } else if (is_multicast_ether_addr(addr)) {
-               err = dev_mc_add_excl(dev, addr);
-       } else {
-               err = -EINVAL;
+               if (IXGBE_MAX_PF_MACVLANS <= netdev_uc_count(dev))
+                       return -ENOMEM;
        }
 
-       /* Only return duplicate errors if NLM_F_EXCL is set */
-       if (err == -EEXIST && !(flags & NLM_F_EXCL))
-               err = 0;
-
-       return err;
+       return ndo_dflt_fdb_add(ndm, tb, dev, addr, flags);
 }
 
 static int ixgbe_ndo_bridge_setlink(struct net_device *dev,
@@ -7830,9 +7726,17 @@ static void *ixgbe_fwd_add(struct net_device *pdev, struct net_device *vdev)
 {
        struct ixgbe_fwd_adapter *fwd_adapter = NULL;
        struct ixgbe_adapter *adapter = netdev_priv(pdev);
+       int used_pools = adapter->num_vfs + adapter->num_rx_pools;
        unsigned int limit;
        int pool, err;
 
+       /* Hardware has a limited number of available pools. Each VF, and the
+        * PF require a pool. Check to ensure we don't attempt to use more
+        * then the available number of pools.
+        */
+       if (used_pools >= IXGBE_MAX_VF_FUNCTIONS)
+               return ERR_PTR(-EINVAL);
+
 #ifdef CONFIG_RPS
        if (vdev->num_rx_queues != vdev->num_tx_queues) {
                netdev_info(pdev, "%s: Only supports a single queue count for TX and RX\n",
index c14d4d89672ff7009168ecf14f98e444e9126ce5..706fc69aa0c51d3824d7c7e8ed0d47ff8f7adbe9 100644 (file)
@@ -250,13 +250,15 @@ static int ixgbe_pci_sriov_enable(struct pci_dev *dev, int num_vfs)
        if (err)
                return err;
 
-       /* While the SR-IOV capability structure reports total VFs to be
-        * 64 we limit the actual number that can be allocated to 63 so
-        * that some transmit/receive resources can be reserved to the
-        * PF.  The PCI bus driver already checks for other values out of
-        * range.
+       /* While the SR-IOV capability structure reports total VFs to be 64,
+        * we have to limit the actual number allocated based on two factors.
+        * First, we reserve some transmit/receive resources for the PF.
+        * Second, VMDQ also uses the same pools that SR-IOV does. We need to
+        * account for this, so that we don't accidentally allocate more VFs
+        * than we have available pools. The PCI bus driver already checks for
+        * other values out of range.
         */
-       if (num_vfs > IXGBE_MAX_VFS_DRV_LIMIT)
+       if ((num_vfs + adapter->num_rx_pools) > IXGBE_MAX_VF_FUNCTIONS)
                return -EPERM;
 
        adapter->num_vfs = num_vfs;
index e6b07c2a01fe3cfdc6458a73646a4754feab8026..dfd55d83bc0335ad46defa9f22923c5125e256d0 100644 (file)
@@ -2194,6 +2194,8 @@ enum {
 #define IXGBE_VFLRE(_i)                ((((_i) & 1) ? 0x001C0 : 0x00600))
 #define IXGBE_VFLREC(_i)               (0x00700 + ((_i) * 4))
 /* Translated register #defines */
+#define IXGBE_PVFTDH(P)                (0x06010 + (0x40 * (P)))
+#define IXGBE_PVFTDT(P)                (0x06018 + (0x40 * (P)))
 #define IXGBE_PVFTDWBAL(P)     (0x06038 + (0x40 * (P)))
 #define IXGBE_PVFTDWBAH(P)     (0x0603C + (0x40 * (P)))
 
@@ -2202,6 +2204,11 @@ enum {
 #define IXGBE_PVFTDWBAHn(q_per_pool, vf_number, vf_q_index) \
                (IXGBE_PVFTDWBAH((q_per_pool)*(vf_number) + (vf_q_index)))
 
+#define IXGBE_PVFTDHN(q_per_pool, vf_number, vf_q_index) \
+               (IXGBE_PVFTDH((q_per_pool)*(vf_number) + (vf_q_index)))
+#define IXGBE_PVFTDTN(q_per_pool, vf_number, vf_q_index) \
+               (IXGBE_PVFTDT((q_per_pool)*(vf_number) + (vf_q_index)))
+
 enum ixgbe_fdir_pballoc_type {
        IXGBE_FDIR_PBALLOC_NONE = 0,
        IXGBE_FDIR_PBALLOC_64K  = 1,
index 4d44d64ae3870c42dd62bb4d1cdfeb96fe9122b9..9cddd56d02c39305a69e13a25c2de88b4d92ccbb 100644 (file)
@@ -434,6 +434,21 @@ static s32 ixgbevf_check_mac_link_vf(struct ixgbe_hw *hw,
        if (!(links_reg & IXGBE_LINKS_UP))
                goto out;
 
+       /* for SFP+ modules and DA cables on 82599 it can take up to 500usecs
+        * before the link status is correct
+        */
+       if (mac->type == ixgbe_mac_82599_vf) {
+               int i;
+
+               for (i = 0; i < 5; i++) {
+                       udelay(100);
+                       links_reg = IXGBE_READ_REG(hw, IXGBE_VFLINKS);
+
+                       if (!(links_reg & IXGBE_LINKS_UP))
+                               goto out;
+               }
+       }
+
        switch (links_reg & IXGBE_LINKS_SPEED_82599) {
        case IXGBE_LINKS_SPEED_10G_82599:
                *speed = IXGBE_LINK_SPEED_10GB_FULL;
index c9f1d1b7ef378bef042b12c9e00f5bf2786594a8..ade067de168959b30c9e7eafc07ed40df0967ee0 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/mbus.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
+#include <linux/if_vlan.h>
 #include <net/ip.h>
 #include <net/ipv6.h>
 #include <linux/io.h>
@@ -1371,15 +1372,16 @@ static u32 mvneta_skb_tx_csum(struct mvneta_port *pp, struct sk_buff *skb)
 {
        if (skb->ip_summed == CHECKSUM_PARTIAL) {
                int ip_hdr_len = 0;
+               __be16 l3_proto = vlan_get_protocol(skb);
                u8 l4_proto;
 
-               if (skb->protocol == htons(ETH_P_IP)) {
+               if (l3_proto == htons(ETH_P_IP)) {
                        struct iphdr *ip4h = ip_hdr(skb);
 
                        /* Calculate IPv4 checksum and L4 checksum */
                        ip_hdr_len = ip4h->ihl;
                        l4_proto = ip4h->protocol;
-               } else if (skb->protocol == htons(ETH_P_IPV6)) {
+               } else if (l3_proto == htons(ETH_P_IPV6)) {
                        struct ipv6hdr *ip6h = ipv6_hdr(skb);
 
                        /* Read l4_protocol from one of IPv6 extra headers */
@@ -1390,7 +1392,7 @@ static u32 mvneta_skb_tx_csum(struct mvneta_port *pp, struct sk_buff *skb)
                        return MVNETA_TX_L4_CSUM_NOT;
 
                return mvneta_txq_desc_csum(skb_network_offset(skb),
-                               skb->protocol, ip_hdr_len, l4_proto);
+                                           l3_proto, ip_hdr_len, l4_proto);
        }
 
        return MVNETA_TX_L4_CSUM_NOT;
index 24b242277ea1c5f1144c7b5e0c042922c44f97d6..264eab7d3b26e0cb53774ae160ecdbe235be1f7b 100644 (file)
@@ -1107,7 +1107,7 @@ static u16 xm_phy_read(struct skge_hw *hw, int port, u16 reg)
 {
        u16 v = 0;
        if (__xm_phy_read(hw, port, reg, &v))
-               pr_warning("%s: phy read timed out\n", hw->dev[port]->name);
+               pr_warn("%s: phy read timed out\n", hw->dev[port]->name);
        return v;
 }
 
@@ -1903,7 +1903,7 @@ static int gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val)
                        return 0;
        }
 
-       pr_warning("%s: phy write timeout\n", hw->dev[port]->name);
+       pr_warn("%s: phy write timeout\n", hw->dev[port]->name);
        return -EIO;
 }
 
@@ -1931,7 +1931,7 @@ static u16 gm_phy_read(struct skge_hw *hw, int port, u16 reg)
 {
        u16 v = 0;
        if (__gm_phy_read(hw, port, reg, &v))
-               pr_warning("%s: phy read timeout\n", hw->dev[port]->name);
+               pr_warn("%s: phy read timeout\n", hw->dev[port]->name);
        return v;
 }
 
index dba48a5ce7ab411c5ef2ec4f13e0296723853c47..bd3366267039bc233e526acf3926d4f8b6fb5638 100644 (file)
@@ -2814,7 +2814,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
 
                default:
                        if (net_ratelimit())
-                               pr_warning("unknown status opcode 0x%x\n", opcode);
+                               pr_warn("unknown status opcode 0x%x\n", opcode);
                }
        } while (hw->st_idx != idx);
 
index bb536aa613f483434f35c4bde31ae36ab9ced290..abddcf8c40aa120c4d4ade2822ccef68d00ea434 100644 (file)
@@ -474,39 +474,12 @@ static int mlx4_en_tunnel_steer_add(struct mlx4_en_priv *priv, unsigned char *ad
                                    int qpn, u64 *reg_id)
 {
        int err;
-       struct mlx4_spec_list spec_eth_outer = { {NULL} };
-       struct mlx4_spec_list spec_vxlan     = { {NULL} };
-       struct mlx4_spec_list spec_eth_inner = { {NULL} };
-
-       struct mlx4_net_trans_rule rule = {
-               .queue_mode = MLX4_NET_TRANS_Q_FIFO,
-               .exclusive = 0,
-               .allow_loopback = 1,
-               .promisc_mode = MLX4_FS_REGULAR,
-               .priority = MLX4_DOMAIN_NIC,
-       };
-
-       __be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16);
 
        if (priv->mdev->dev->caps.tunnel_offload_mode != MLX4_TUNNEL_OFFLOAD_MODE_VXLAN)
                return 0; /* do nothing */
 
-       rule.port = priv->port;
-       rule.qpn = qpn;
-       INIT_LIST_HEAD(&rule.list);
-
-       spec_eth_outer.id = MLX4_NET_TRANS_RULE_ID_ETH;
-       memcpy(spec_eth_outer.eth.dst_mac, addr, ETH_ALEN);
-       memcpy(spec_eth_outer.eth.dst_mac_msk, &mac_mask, ETH_ALEN);
-
-       spec_vxlan.id = MLX4_NET_TRANS_RULE_ID_VXLAN;    /* any vxlan header */
-       spec_eth_inner.id = MLX4_NET_TRANS_RULE_ID_ETH;  /* any inner eth header */
-
-       list_add_tail(&spec_eth_outer.list, &rule.list);
-       list_add_tail(&spec_vxlan.list,     &rule.list);
-       list_add_tail(&spec_eth_inner.list, &rule.list);
-
-       err = mlx4_flow_attach(priv->mdev->dev, &rule, reg_id);
+       err = mlx4_tunnel_steer_add(priv->mdev->dev, addr, priv->port, qpn,
+                                   MLX4_DOMAIN_NIC, reg_id);
        if (err) {
                en_err(priv, "failed to add vxlan steering rule, err %d\n", err);
                return err;
index 9c909d23f14c4eda34ce8f03215b76aa29639894..14686b6f4bc591d1fd4d6e2f0c6dd9e71d0288b5 100644 (file)
@@ -588,6 +588,8 @@ static struct sk_buff *mlx4_en_rx_skb(struct mlx4_en_priv *priv,
                skb_copy_to_linear_data(skb, va, length);
                skb->tail += length;
        } else {
+               unsigned int pull_len;
+
                /* Move relevant fragments to skb */
                used_frags = mlx4_en_complete_rx_desc(priv, rx_desc, frags,
                                                        skb, length);
@@ -597,16 +599,17 @@ static struct sk_buff *mlx4_en_rx_skb(struct mlx4_en_priv *priv,
                }
                skb_shinfo(skb)->nr_frags = used_frags;
 
+               pull_len = eth_get_headlen(va, SMALL_PACKET_SIZE);
                /* Copy headers into the skb linear buffer */
-               memcpy(skb->data, va, HEADER_COPY_SIZE);
-               skb->tail += HEADER_COPY_SIZE;
+               memcpy(skb->data, va, pull_len);
+               skb->tail += pull_len;
 
                /* Skip headers in first fragment */
-               skb_shinfo(skb)->frags[0].page_offset += HEADER_COPY_SIZE;
+               skb_shinfo(skb)->frags[0].page_offset += pull_len;
 
                /* Adjust size of first fragment */
-               skb_frag_size_sub(&skb_shinfo(skb)->frags[0], HEADER_COPY_SIZE);
-               skb->data_len = length - HEADER_COPY_SIZE;
+               skb_frag_size_sub(&skb_shinfo(skb)->frags[0], pull_len);
+               skb->data_len = length - pull_len;
        }
        return skb;
 }
@@ -769,7 +772,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
                                        gro_skb->ip_summed = CHECKSUM_UNNECESSARY;
 
                                        if (l2_tunnel)
-                                               gro_skb->encapsulation = 1;
+                                               gro_skb->csum_level = 1;
                                        if ((cqe->vlan_my_qpn &
                                            cpu_to_be32(MLX4_CQE_VLAN_PRESENT_MASK)) &&
                                            (dev->features & NETIF_F_HW_VLAN_CTAG_RX)) {
@@ -823,8 +826,8 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
                skb->protocol = eth_type_trans(skb, dev);
                skb_record_rx_queue(skb, cq->ring);
 
-               if (l2_tunnel)
-                       skb->encapsulation = 1;
+               if (l2_tunnel && ip_summed == CHECKSUM_UNNECESSARY)
+                       skb->csum_level = 1;
 
                if (dev->features & NETIF_F_RXHASH)
                        skb_set_hash(skb,
index dae3da6d8dd08979e4a4ba3f0f3c7413f10198cd..bc8f51c77d8082c1ab420a25394f32f1a59de20e 100644 (file)
@@ -319,7 +319,7 @@ static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv,
                        }
                }
        }
-       dev_kfree_skb_any(skb);
+       dev_consume_skb_any(skb);
        return tx_info->nr_txbb;
 }
 
index d80e7a6fac74c4381cea11f946c889216a5ce05d..ca0f98c951054945cd29fc3be2284fc7eeb7d729 100644 (file)
@@ -1020,6 +1020,44 @@ int mlx4_flow_detach(struct mlx4_dev *dev, u64 reg_id)
 }
 EXPORT_SYMBOL_GPL(mlx4_flow_detach);
 
+int mlx4_tunnel_steer_add(struct mlx4_dev *dev, unsigned char *addr,
+                         int port, int qpn, u16 prio, u64 *reg_id)
+{
+       int err;
+       struct mlx4_spec_list spec_eth_outer = { {NULL} };
+       struct mlx4_spec_list spec_vxlan     = { {NULL} };
+       struct mlx4_spec_list spec_eth_inner = { {NULL} };
+
+       struct mlx4_net_trans_rule rule = {
+               .queue_mode = MLX4_NET_TRANS_Q_FIFO,
+               .exclusive = 0,
+               .allow_loopback = 1,
+               .promisc_mode = MLX4_FS_REGULAR,
+       };
+
+       __be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16);
+
+       rule.port = port;
+       rule.qpn = qpn;
+       rule.priority = prio;
+       INIT_LIST_HEAD(&rule.list);
+
+       spec_eth_outer.id = MLX4_NET_TRANS_RULE_ID_ETH;
+       memcpy(spec_eth_outer.eth.dst_mac, addr, ETH_ALEN);
+       memcpy(spec_eth_outer.eth.dst_mac_msk, &mac_mask, ETH_ALEN);
+
+       spec_vxlan.id = MLX4_NET_TRANS_RULE_ID_VXLAN;    /* any vxlan header */
+       spec_eth_inner.id = MLX4_NET_TRANS_RULE_ID_ETH;  /* any inner eth header */
+
+       list_add_tail(&spec_eth_outer.list, &rule.list);
+       list_add_tail(&spec_vxlan.list,     &rule.list);
+       list_add_tail(&spec_eth_inner.list, &rule.list);
+
+       err = mlx4_flow_attach(dev, &rule, reg_id);
+       return err;
+}
+EXPORT_SYMBOL(mlx4_tunnel_steer_add);
+
 int mlx4_FLOW_STEERING_IB_UC_QP_RANGE(struct mlx4_dev *dev, u32 min_range_qpn,
                                      u32 max_range_qpn)
 {
index 5020fd47825d65c359f010a9bcbf0f2e9a0ceaf7..2f12c88c66abfa1cd0bb0e099e4a33a761327fd6 100644 (file)
@@ -206,7 +206,7 @@ static int moxart_rx_poll(struct napi_struct *napi, int budget)
        int rx_head = priv->rx_head;
        int rx = 0;
 
-       while (1) {
+       while (rx < budget) {
                desc = priv->rx_desc_base + (RX_REG_DESC_SIZE * rx_head);
                desc0 = readl(desc + RX_REG_OFFSET_DESC0);
 
@@ -218,7 +218,7 @@ static int moxart_rx_poll(struct napi_struct *napi, int budget)
                        net_dbg_ratelimited("packet error\n");
                        priv->stats.rx_dropped++;
                        priv->stats.rx_errors++;
-                       continue;
+                       goto rx_next;
                }
 
                len = desc0 & RX_DESC0_FRAME_LEN_MASK;
@@ -226,13 +226,19 @@ static int moxart_rx_poll(struct napi_struct *napi, int budget)
                if (len > RX_BUF_SIZE)
                        len = RX_BUF_SIZE;
 
-               skb = build_skb(priv->rx_buf[rx_head], priv->rx_buf_size);
+               dma_sync_single_for_cpu(&ndev->dev,
+                                       priv->rx_mapping[rx_head],
+                                       priv->rx_buf_size, DMA_FROM_DEVICE);
+               skb = netdev_alloc_skb_ip_align(ndev, len);
+
                if (unlikely(!skb)) {
-                       net_dbg_ratelimited("build_skb failed\n");
+                       net_dbg_ratelimited("netdev_alloc_skb_ip_align failed\n");
                        priv->stats.rx_dropped++;
                        priv->stats.rx_errors++;
+                       goto rx_next;
                }
 
+               memcpy(skb->data, priv->rx_buf[rx_head], len);
                skb_put(skb, len);
                skb->protocol = eth_type_trans(skb, ndev);
                napi_gro_receive(&priv->napi, skb);
@@ -244,18 +250,15 @@ static int moxart_rx_poll(struct napi_struct *napi, int budget)
                if (desc0 & RX_DESC0_MULTICAST)
                        priv->stats.multicast++;
 
+rx_next:
                writel(RX_DESC0_DMA_OWN, desc + RX_REG_OFFSET_DESC0);
 
                rx_head = RX_NEXT(rx_head);
                priv->rx_head = rx_head;
-
-               if (rx >= budget)
-                       break;
        }
 
        if (rx < budget) {
-               napi_gro_flush(napi, false);
-               __napi_complete(napi);
+               napi_complete(napi);
        }
 
        priv->reg_imr |= RPKT_FINISH_M;
@@ -346,10 +349,12 @@ static int moxart_mac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                len = ETH_ZLEN;
        }
 
-       txdes1 = readl(desc + TX_REG_OFFSET_DESC1);
-       txdes1 |= TX_DESC1_LTS | TX_DESC1_FTS;
-       txdes1 &= ~(TX_DESC1_FIFO_COMPLETE | TX_DESC1_INTR_COMPLETE);
-       txdes1 |= (len & TX_DESC1_BUF_SIZE_MASK);
+       dma_sync_single_for_device(&ndev->dev, priv->tx_mapping[tx_head],
+                                  priv->tx_buf_size, DMA_TO_DEVICE);
+
+       txdes1 = TX_DESC1_LTS | TX_DESC1_FTS | (len & TX_DESC1_BUF_SIZE_MASK);
+       if (tx_head == TX_DESC_NUM_MASK)
+               txdes1 |= TX_DESC1_END;
        writel(txdes1, desc + TX_REG_OFFSET_DESC1);
        writel(TX_DESC0_DMA_OWN, desc + TX_REG_OFFSET_DESC0);
 
@@ -465,8 +470,7 @@ static int moxart_mac_probe(struct platform_device *pdev)
        spin_lock_init(&priv->txlock);
 
        priv->tx_buf_size = TX_BUF_SIZE;
-       priv->rx_buf_size = RX_BUF_SIZE +
-                           SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+       priv->rx_buf_size = RX_BUF_SIZE;
 
        priv->tx_desc_base = dma_alloc_coherent(NULL, TX_REG_DESC_SIZE *
                                                TX_DESC_NUM, &priv->tx_base,
index 925b296d8ab84d8497d5a85b2bd5dda8b0c08aa9..f39cae620f61568688c79415c6dbf9ebbf96ff90 100644 (file)
@@ -1481,7 +1481,7 @@ static int phy_init(struct net_device *dev)
        }
 
        /* phy vendor specific configuration */
-       if ((np->phy_oui == PHY_OUI_CICADA)) {
+       if (np->phy_oui == PHY_OUI_CICADA) {
                if (init_cicada(dev, np, phyinterface)) {
                        netdev_info(dev, "%s: phy init failed\n",
                                    pci_name(np->pci_dev));
index 8706c0dbd0c36a2c3b7af167eaa4c29cda3905a5..a44a03c45014903a6410ebe2d665f3651ee30db2 100644 (file)
@@ -1220,6 +1220,9 @@ static int lpc_eth_open(struct net_device *ndev)
 
        __lpc_eth_clock_enable(pldat, true);
 
+       /* Suspended PHY makes LPC ethernet core block, so resume now */
+       phy_resume(pldat->phy_dev);
+
        /* Reset and initialize */
        __lpc_eth_reset(pldat);
        __lpc_eth_init(pldat);
index 2d6b148528ddf42f7b613dde08344ada5ad7431f..fa2db41e02f85d472d89b30ddd22be53bee85280 100644 (file)
@@ -693,11 +693,11 @@ static void yellowfin_tx_timeout(struct net_device *dev)
        /* Note: these should be KERN_DEBUG. */
        if (yellowfin_debug) {
                int i;
-               pr_warning("  Rx ring %p: ", yp->rx_ring);
+               pr_warn("  Rx ring %p: ", yp->rx_ring);
                for (i = 0; i < RX_RING_SIZE; i++)
                        pr_cont(" %08x", yp->rx_ring[i].result_status);
                pr_cont("\n");
-               pr_warning("  Tx ring %p: ", yp->tx_ring);
+               pr_warn("  Tx ring %p: ", yp->tx_ring);
                for (i = 0; i < TX_RING_SIZE; i++)
                        pr_cont(" %04x /%08x",
                               yp->tx_status[i].tx_errs,
index 1159031f885b10bde26d5119e0aeaedd5641ee0c..32456c79cc732148a9eedd8bfbbbad5235c6d214 100644 (file)
@@ -1477,9 +1477,8 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        u32 val;
 
        if (pdev->revision >= NX_P3_A0 && pdev->revision <= NX_P3_B1) {
-               pr_warning("%s: chip revisions between 0x%x-0x%x "
-                               "will not be enabled.\n",
-                               module_name(THIS_MODULE), NX_P3_A0, NX_P3_B1);
+               pr_warn("%s: chip revisions between 0x%x-0x%x will not be enabled\n",
+                       module_name(THIS_MODULE), NX_P3_A0, NX_P3_B1);
                return -ENODEV;
        }
 
index 16039d1497b84a68efb84aa8f66aa0fd250418f4..e56c1bb361412144e2fa60cc6b2b21b3ecb35245 100644 (file)
@@ -39,8 +39,8 @@
 
 #define _QLCNIC_LINUX_MAJOR 5
 #define _QLCNIC_LINUX_MINOR 3
-#define _QLCNIC_LINUX_SUBVERSION 61
-#define QLCNIC_LINUX_VERSIONID  "5.3.61"
+#define _QLCNIC_LINUX_SUBVERSION 62
+#define QLCNIC_LINUX_VERSIONID  "5.3.62"
 #define QLCNIC_DRV_IDC_VER  0x01
 #define QLCNIC_DRIVER_VERSION  ((_QLCNIC_LINUX_MAJOR << 16) |\
                 (_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION))
@@ -268,7 +268,7 @@ struct qlcnic_fdt {
        u16     cksum;
        u16     unused;
        u8      model[16];
-       u16     mfg_id;
+       u     mfg_id;
        u16     id;
        u8      flag;
        u8      erase_cmd;
@@ -540,6 +540,8 @@ struct qlcnic_hardware_context {
        u8 lb_mode;
        u16 vxlan_port;
        struct device *hwmon_dev;
+       u32 post_mode;
+       bool run_post;
 };
 
 struct qlcnic_adapter_stats {
@@ -2283,6 +2285,7 @@ extern const struct ethtool_ops qlcnic_ethtool_failed_ops;
 
 #define PCI_DEVICE_ID_QLOGIC_QLE824X           0x8020
 #define PCI_DEVICE_ID_QLOGIC_QLE834X           0x8030
+#define PCI_DEVICE_ID_QLOGIC_QLE8830           0x8830
 #define PCI_DEVICE_ID_QLOGIC_VF_QLE834X        0x8430
 #define PCI_DEVICE_ID_QLOGIC_QLE844X           0x8040
 #define PCI_DEVICE_ID_QLOGIC_VF_QLE844X        0x8440
@@ -2307,6 +2310,7 @@ static inline bool qlcnic_83xx_check(struct qlcnic_adapter *adapter)
        bool status;
 
        status = ((device == PCI_DEVICE_ID_QLOGIC_QLE834X) ||
+                 (device == PCI_DEVICE_ID_QLOGIC_QLE8830) ||
                  (device == PCI_DEVICE_ID_QLOGIC_QLE844X) ||
                  (device == PCI_DEVICE_ID_QLOGIC_VF_QLE844X) ||
                  (device == PCI_DEVICE_ID_QLOGIC_VF_QLE834X)) ? true : false;
@@ -2362,6 +2366,19 @@ static inline u32 qlcnic_get_vnic_func_count(struct qlcnic_adapter *adapter)
                return QLC_DEFAULT_VNIC_COUNT;
 }
 
+static inline void qlcnic_swap32_buffer(u32 *buffer, int count)
+{
+#if defined(__BIG_ENDIAN)
+       u32 *tmp = buffer;
+       int i;
+
+       for (i = 0; i < count; i++) {
+               *tmp = swab32(*tmp);
+               tmp++;
+       }
+#endif
+}
+
 #ifdef CONFIG_QLCNIC_HWMON
 void qlcnic_register_hwmon_dev(struct qlcnic_adapter *);
 void qlcnic_unregister_hwmon_dev(struct qlcnic_adapter *);
index a4a4ec0b68f8d5e9d7b0c6f3ed5050b5787a37c4..840bf36b5e9d0d8ac5ddca14cc5e1afca26191f8 100644 (file)
@@ -35,6 +35,35 @@ static void qlcnic_83xx_get_beacon_state(struct qlcnic_adapter *);
 #define QLC_SKIP_INACTIVE_PCI_REGS     7
 #define QLC_MAX_LEGACY_FUNC_SUPP       8
 
+/* 83xx Module type */
+#define QLC_83XX_MODULE_FIBRE_10GBASE_LRM      0x1 /* 10GBase-LRM */
+#define QLC_83XX_MODULE_FIBRE_10GBASE_LR       0x2 /* 10GBase-LR */
+#define QLC_83XX_MODULE_FIBRE_10GBASE_SR       0x3 /* 10GBase-SR */
+#define QLC_83XX_MODULE_DA_10GE_PASSIVE_CP     0x4 /* 10GE passive
+                                                    * copper(compliant)
+                                                    */
+#define QLC_83XX_MODULE_DA_10GE_ACTIVE_CP      0x5 /* 10GE active limiting
+                                                    * copper(compliant)
+                                                    */
+#define QLC_83XX_MODULE_DA_10GE_LEGACY_CP      0x6 /* 10GE passive copper
+                                                    * (legacy, best effort)
+                                                    */
+#define QLC_83XX_MODULE_FIBRE_1000BASE_SX      0x7 /* 1000Base-SX */
+#define QLC_83XX_MODULE_FIBRE_1000BASE_LX      0x8 /* 1000Base-LX */
+#define QLC_83XX_MODULE_FIBRE_1000BASE_CX      0x9 /* 1000Base-CX */
+#define QLC_83XX_MODULE_TP_1000BASE_T          0xa /* 1000Base-T*/
+#define QLC_83XX_MODULE_DA_1GE_PASSIVE_CP      0xb /* 1GE passive copper
+                                                    * (legacy, best effort)
+                                                    */
+#define QLC_83XX_MODULE_UNKNOWN                        0xf /* Unknown module type */
+
+/* Port types */
+#define QLC_83XX_10_CAPABLE     BIT_8
+#define QLC_83XX_100_CAPABLE    BIT_9
+#define QLC_83XX_1G_CAPABLE     BIT_10
+#define QLC_83XX_10G_CAPABLE    BIT_11
+#define QLC_83XX_AUTONEG_ENABLE         BIT_15
+
 static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl[] = {
        {QLCNIC_CMD_CONFIGURE_IP_ADDR, 6, 1},
        {QLCNIC_CMD_CONFIG_INTRPT, 18, 34},
@@ -667,6 +696,7 @@ void qlcnic_83xx_write_crb(struct qlcnic_adapter *adapter, char *buf,
 
 int qlcnic_83xx_get_port_info(struct qlcnic_adapter *adapter)
 {
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
        int status;
 
        status = qlcnic_83xx_get_port_config(adapter);
@@ -674,13 +704,20 @@ int qlcnic_83xx_get_port_info(struct qlcnic_adapter *adapter)
                dev_err(&adapter->pdev->dev,
                        "Get Port Info failed\n");
        } else {
-               if (QLC_83XX_SFP_10G_CAPABLE(adapter->ahw->port_config))
-                       adapter->ahw->port_type = QLCNIC_XGBE;
-               else
-                       adapter->ahw->port_type = QLCNIC_GBE;
 
-               if (QLC_83XX_AUTONEG(adapter->ahw->port_config))
-                       adapter->ahw->link_autoneg = AUTONEG_ENABLE;
+               if (ahw->port_config & QLC_83XX_10G_CAPABLE) {
+                       ahw->port_type = QLCNIC_XGBE;
+               } else if (ahw->port_config & QLC_83XX_10_CAPABLE ||
+                          ahw->port_config & QLC_83XX_100_CAPABLE ||
+                          ahw->port_config & QLC_83XX_1G_CAPABLE) {
+                       ahw->port_type = QLCNIC_GBE;
+               } else {
+                       ahw->port_type = QLCNIC_XGBE;
+               }
+
+               if (QLC_83XX_AUTONEG(ahw->port_config))
+                       ahw->link_autoneg = AUTONEG_ENABLE;
+
        }
        return status;
 }
@@ -2603,7 +2640,7 @@ int qlcnic_83xx_lockless_flash_read32(struct qlcnic_adapter *adapter,
        }
 
        qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_DIRECT_WINDOW,
-                                    (addr));
+                                    (addr & 0xFFFF0000));
 
        range = flash_offset + (count * sizeof(u32));
        /* Check if data is spread across multiple sectors */
@@ -2664,7 +2701,7 @@ static int qlcnic_83xx_poll_flash_status_reg(struct qlcnic_adapter *adapter)
                    QLC_83XX_FLASH_STATUS_READY)
                        break;
 
-               msleep(QLC_83XX_FLASH_STATUS_REG_POLL_DELAY);
+               usleep_range(1000, 1100);
        } while (--retries);
 
        if (!retries)
@@ -2753,7 +2790,7 @@ int qlcnic_83xx_read_flash_descriptor_table(struct qlcnic_adapter *adapter)
        ret = qlcnic_83xx_lockless_flash_read32(adapter, QLCNIC_FDT_LOCATION,
                                                (u8 *)&adapter->ahw->fdt,
                                                count);
-
+       qlcnic_swap32_buffer((u32 *)&adapter->ahw->fdt, count);
        qlcnic_83xx_unlock_flash(adapter);
        return ret;
 }
@@ -2788,7 +2825,7 @@ int qlcnic_83xx_erase_flash_sector(struct qlcnic_adapter *adapter,
 
        addr1 = (sector_start_addr & 0xFF) << 16;
        addr2 = (sector_start_addr & 0xFF0000) >> 16;
-       reversed_addr = addr1 | addr2;
+       reversed_addr = addr1 | addr2 | (sector_start_addr & 0xFF00);
 
        qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_WRDATA,
                                     reversed_addr);
@@ -3176,22 +3213,33 @@ int qlcnic_83xx_test_link(struct qlcnic_adapter *adapter)
                        break;
                }
                config = cmd.rsp.arg[3];
-               if (QLC_83XX_SFP_PRESENT(config)) {
-                       switch (ahw->module_type) {
-                       case LINKEVENT_MODULE_OPTICAL_UNKNOWN:
-                       case LINKEVENT_MODULE_OPTICAL_SRLR:
-                       case LINKEVENT_MODULE_OPTICAL_LRM:
-                       case LINKEVENT_MODULE_OPTICAL_SFP_1G:
-                               ahw->supported_type = PORT_FIBRE;
-                               break;
-                       case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE:
-                       case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN:
-                       case LINKEVENT_MODULE_TWINAX:
-                               ahw->supported_type = PORT_TP;
-                               break;
-                       default:
-                               ahw->supported_type = PORT_OTHER;
-                       }
+               switch (QLC_83XX_SFP_MODULE_TYPE(config)) {
+               case QLC_83XX_MODULE_FIBRE_10GBASE_LRM:
+               case QLC_83XX_MODULE_FIBRE_10GBASE_LR:
+               case QLC_83XX_MODULE_FIBRE_10GBASE_SR:
+                       ahw->supported_type = PORT_FIBRE;
+                       ahw->port_type = QLCNIC_XGBE;
+                       break;
+               case QLC_83XX_MODULE_FIBRE_1000BASE_SX:
+               case QLC_83XX_MODULE_FIBRE_1000BASE_LX:
+               case QLC_83XX_MODULE_FIBRE_1000BASE_CX:
+                       ahw->supported_type = PORT_FIBRE;
+                       ahw->port_type = QLCNIC_GBE;
+                       break;
+               case QLC_83XX_MODULE_TP_1000BASE_T:
+                       ahw->supported_type = PORT_TP;
+                       ahw->port_type = QLCNIC_GBE;
+                       break;
+               case QLC_83XX_MODULE_DA_10GE_PASSIVE_CP:
+               case QLC_83XX_MODULE_DA_10GE_ACTIVE_CP:
+               case QLC_83XX_MODULE_DA_10GE_LEGACY_CP:
+               case QLC_83XX_MODULE_DA_1GE_PASSIVE_CP:
+                       ahw->supported_type = PORT_DA;
+                       ahw->port_type = QLCNIC_XGBE;
+                       break;
+               default:
+                       ahw->supported_type = PORT_OTHER;
+                       ahw->port_type = QLCNIC_XGBE;
                }
                if (config & 1)
                        err = 1;
@@ -3204,9 +3252,9 @@ out:
 int qlcnic_83xx_get_settings(struct qlcnic_adapter *adapter,
                             struct ethtool_cmd *ecmd)
 {
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
        u32 config = 0;
        int status = 0;
-       struct qlcnic_hardware_context *ahw = adapter->ahw;
 
        if (!test_bit(__QLCNIC_MAINTENANCE_MODE, &adapter->state)) {
                /* Get port configuration info */
@@ -3229,20 +3277,41 @@ int qlcnic_83xx_get_settings(struct qlcnic_adapter *adapter,
                ecmd->autoneg = AUTONEG_DISABLE;
        }
 
-       if (ahw->port_type == QLCNIC_XGBE) {
-               ecmd->supported = SUPPORTED_10000baseT_Full;
-               ecmd->advertising = ADVERTISED_10000baseT_Full;
+       ecmd->supported = (SUPPORTED_10baseT_Full |
+                          SUPPORTED_100baseT_Full |
+                          SUPPORTED_1000baseT_Full |
+                          SUPPORTED_10000baseT_Full |
+                          SUPPORTED_Autoneg);
+
+       if (ecmd->autoneg == AUTONEG_ENABLE) {
+               if (ahw->port_config & QLC_83XX_10_CAPABLE)
+                       ecmd->advertising |= SUPPORTED_10baseT_Full;
+               if (ahw->port_config & QLC_83XX_100_CAPABLE)
+                       ecmd->advertising |= SUPPORTED_100baseT_Full;
+               if (ahw->port_config & QLC_83XX_1G_CAPABLE)
+                       ecmd->advertising |= SUPPORTED_1000baseT_Full;
+               if (ahw->port_config & QLC_83XX_10G_CAPABLE)
+                       ecmd->advertising |= SUPPORTED_10000baseT_Full;
+               if (ahw->port_config & QLC_83XX_AUTONEG_ENABLE)
+                       ecmd->advertising |= ADVERTISED_Autoneg;
        } else {
-               ecmd->supported = (SUPPORTED_10baseT_Half |
-                                  SUPPORTED_10baseT_Full |
-                                  SUPPORTED_100baseT_Half |
-                                  SUPPORTED_100baseT_Full |
-                                  SUPPORTED_1000baseT_Half |
-                                  SUPPORTED_1000baseT_Full);
-               ecmd->advertising = (ADVERTISED_100baseT_Half |
-                                    ADVERTISED_100baseT_Full |
-                                    ADVERTISED_1000baseT_Half |
-                                    ADVERTISED_1000baseT_Full);
+               switch (ahw->link_speed) {
+               case SPEED_10:
+                       ecmd->advertising = SUPPORTED_10baseT_Full;
+                       break;
+               case SPEED_100:
+                       ecmd->advertising = SUPPORTED_100baseT_Full;
+                       break;
+               case SPEED_1000:
+                       ecmd->advertising = SUPPORTED_1000baseT_Full;
+                       break;
+               case SPEED_10000:
+                       ecmd->advertising = SUPPORTED_10000baseT_Full;
+                       break;
+               default:
+                       break;
+               }
+
        }
 
        switch (ahw->supported_type) {
@@ -3258,6 +3327,12 @@ int qlcnic_83xx_get_settings(struct qlcnic_adapter *adapter,
                ecmd->port = PORT_TP;
                ecmd->transceiver = XCVR_INTERNAL;
                break;
+       case PORT_DA:
+               ecmd->supported |= SUPPORTED_FIBRE;
+               ecmd->advertising |= ADVERTISED_FIBRE;
+               ecmd->port = PORT_DA;
+               ecmd->transceiver = XCVR_EXTERNAL;
+               break;
        default:
                ecmd->supported |= SUPPORTED_FIBRE;
                ecmd->advertising |= ADVERTISED_FIBRE;
@@ -3272,35 +3347,60 @@ int qlcnic_83xx_get_settings(struct qlcnic_adapter *adapter,
 int qlcnic_83xx_set_settings(struct qlcnic_adapter *adapter,
                             struct ethtool_cmd *ecmd)
 {
-       int status = 0;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
        u32 config = adapter->ahw->port_config;
+       int status = 0;
 
-       if (ecmd->autoneg)
-               adapter->ahw->port_config |= BIT_15;
-
-       switch (ethtool_cmd_speed(ecmd)) {
-       case SPEED_10:
-               adapter->ahw->port_config |= BIT_8;
-               break;
-       case SPEED_100:
-               adapter->ahw->port_config |= BIT_9;
-               break;
-       case SPEED_1000:
-               adapter->ahw->port_config |= BIT_10;
-               break;
-       case SPEED_10000:
-               adapter->ahw->port_config |= BIT_11;
-               break;
-       default:
-               return -EINVAL;
+       /* 83xx devices do not support Half duplex */
+       if (ecmd->duplex == DUPLEX_HALF) {
+                       netdev_info(adapter->netdev,
+                                   "Half duplex mode not supported\n");
+                       return -EINVAL;
        }
 
+       if (ecmd->autoneg) {
+               ahw->port_config |= QLC_83XX_AUTONEG_ENABLE;
+               ahw->port_config |= (QLC_83XX_100_CAPABLE |
+                                    QLC_83XX_1G_CAPABLE |
+                                    QLC_83XX_10G_CAPABLE);
+       } else { /* force speed */
+               ahw->port_config &= ~QLC_83XX_AUTONEG_ENABLE;
+               switch (ethtool_cmd_speed(ecmd)) {
+               case SPEED_10:
+                       ahw->port_config &= ~(QLC_83XX_100_CAPABLE |
+                                             QLC_83XX_1G_CAPABLE |
+                                             QLC_83XX_10G_CAPABLE);
+                       ahw->port_config |= QLC_83XX_10_CAPABLE;
+                       break;
+               case SPEED_100:
+                       ahw->port_config &= ~(QLC_83XX_10_CAPABLE |
+                                             QLC_83XX_1G_CAPABLE |
+                                             QLC_83XX_10G_CAPABLE);
+                       ahw->port_config |= QLC_83XX_100_CAPABLE;
+                       break;
+               case SPEED_1000:
+                       ahw->port_config &= ~(QLC_83XX_10_CAPABLE |
+                                             QLC_83XX_100_CAPABLE |
+                                             QLC_83XX_10G_CAPABLE);
+                       ahw->port_config |= QLC_83XX_1G_CAPABLE;
+                       break;
+               case SPEED_10000:
+                       ahw->port_config &= ~(QLC_83XX_10_CAPABLE |
+                                             QLC_83XX_100_CAPABLE |
+                                             QLC_83XX_1G_CAPABLE);
+                       ahw->port_config |= QLC_83XX_10G_CAPABLE;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       }
        status = qlcnic_83xx_set_port_config(adapter);
        if (status) {
-               dev_info(&adapter->pdev->dev,
-                        "Failed to Set Link Speed and autoneg.\n");
-               adapter->ahw->port_config = config;
+               netdev_info(adapter->netdev,
+                           "Failed to Set Link Speed and autoneg.\n");
+               ahw->port_config = config;
        }
+
        return status;
 }
 
index 2bf101a47d02db1afbd153e032aab728f2ecb159..f3346a3779d3c36c2f91d4703feb75dc500e39df 100644 (file)
@@ -83,6 +83,7 @@
 /* Firmware image definitions */
 #define QLC_83XX_BOOTLOADER_FLASH_ADDR 0x10000
 #define QLC_83XX_FW_FILE_NAME          "83xx_fw.bin"
+#define QLC_83XX_POST_FW_FILE_NAME     "83xx_post_fw.bin"
 #define QLC_84XX_FW_FILE_NAME          "84xx_fw.bin"
 #define QLC_83XX_BOOT_FROM_FLASH       0
 #define QLC_83XX_BOOT_FROM_FILE                0x12345678
@@ -360,7 +361,6 @@ enum qlcnic_83xx_states {
 #define QLC_83XX_SFP_MODULE_TYPE(data)         (((data) >> 4) & 0x1F)
 #define QLC_83XX_SFP_CU_LENGTH(data)           (LSB((data) >> 16))
 #define QLC_83XX_SFP_TX_FAULT(data)            ((data) & BIT_10)
-#define QLC_83XX_SFP_10G_CAPABLE(data)         ((data) & BIT_11)
 #define QLC_83XX_LINK_STATS(data)              ((data) & BIT_0)
 #define QLC_83XX_CURRENT_LINK_SPEED(data)      (((data) >> 3) & 7)
 #define QLC_83XX_LINK_PAUSE(data)              (((data) >> 6) & 3)
index f33559b725283cf69b08e80a8179fb488b89acb2..9a2cfe4efac64c4b3f6073c1f5790d82ceb61c3d 100644 (file)
@@ -1378,31 +1378,45 @@ static int qlcnic_83xx_copy_fw_file(struct qlcnic_adapter *adapter)
 {
        struct qlc_83xx_fw_info *fw_info = adapter->ahw->fw_info;
        const struct firmware *fw = fw_info->fw;
-       u32 dest, *p_cache;
+       u32 dest, *p_cache, *temp;
        int i, ret = -EIO;
+       __le32 *temp_le;
        u8 data[16];
        size_t size;
        u64 addr;
 
+       temp = kzalloc(fw->size, GFP_KERNEL);
+       if (!temp) {
+               release_firmware(fw);
+               fw_info->fw = NULL;
+               return -ENOMEM;
+       }
+
+       temp_le = (__le32 *)fw->data;
+
+       /* FW image in file is in little endian, swap the data to nullify
+        * the effect of writel() operation on big endian platform.
+        */
+       for (i = 0; i < fw->size / sizeof(u32); i++)
+               temp[i] = __le32_to_cpu(temp_le[i]);
+
        dest = QLCRDX(adapter->ahw, QLCNIC_FW_IMAGE_ADDR);
        size = (fw->size & ~0xF);
-       p_cache = (u32 *)fw->data;
+       p_cache = temp;
        addr = (u64)dest;
 
        ret = qlcnic_ms_mem_write128(adapter, addr,
                                     p_cache, size / 16);
        if (ret) {
                dev_err(&adapter->pdev->dev, "MS memory write failed\n");
-               release_firmware(fw);
-               fw_info->fw = NULL;
-               return -EIO;
+               goto exit;
        }
 
        /* alignment check */
        if (fw->size & 0xF) {
                addr = dest + size;
                for (i = 0; i < (fw->size & 0xF); i++)
-                       data[i] = fw->data[size + i];
+                       data[i] = temp[size + i];
                for (; i < 16; i++)
                        data[i] = 0;
                ret = qlcnic_ms_mem_write128(adapter, addr,
@@ -1410,15 +1424,16 @@ static int qlcnic_83xx_copy_fw_file(struct qlcnic_adapter *adapter)
                if (ret) {
                        dev_err(&adapter->pdev->dev,
                                "MS memory write failed\n");
-                       release_firmware(fw);
-                       fw_info->fw = NULL;
-                       return -EIO;
+                       goto exit;
                }
        }
+
+exit:
        release_firmware(fw);
        fw_info->fw = NULL;
+       kfree(temp);
 
-       return 0;
+       return ret;
 }
 
 static void qlcnic_83xx_dump_pause_control_regs(struct qlcnic_adapter *adapter)
@@ -2060,6 +2075,121 @@ static void qlcnic_83xx_init_hw(struct qlcnic_adapter *p_dev)
                dev_err(&p_dev->pdev->dev, "%s: failed\n", __func__);
 }
 
+/* POST FW related definations*/
+#define QLC_83XX_POST_SIGNATURE_REG    0x41602014
+#define QLC_83XX_POST_MODE_REG         0x41602018
+#define QLC_83XX_POST_FAST_MODE                0
+#define QLC_83XX_POST_MEDIUM_MODE      1
+#define QLC_83XX_POST_SLOW_MODE                2
+
+/* POST Timeout values in milliseconds */
+#define QLC_83XX_POST_FAST_MODE_TIMEOUT        690
+#define QLC_83XX_POST_MED_MODE_TIMEOUT 2930
+#define QLC_83XX_POST_SLOW_MODE_TIMEOUT        7500
+
+/* POST result values */
+#define QLC_83XX_POST_PASS                     0xfffffff0
+#define QLC_83XX_POST_ASIC_STRESS_TEST_FAIL    0xffffffff
+#define QLC_83XX_POST_DDR_TEST_FAIL            0xfffffffe
+#define QLC_83XX_POST_ASIC_MEMORY_TEST_FAIL    0xfffffffc
+#define QLC_83XX_POST_FLASH_TEST_FAIL          0xfffffff8
+
+static int qlcnic_83xx_run_post(struct qlcnic_adapter *adapter)
+{
+       struct qlc_83xx_fw_info *fw_info = adapter->ahw->fw_info;
+       struct device *dev = &adapter->pdev->dev;
+       int timeout, count, ret = 0;
+       u32 signature;
+
+       /* Set timeout values with extra 2 seconds of buffer */
+       switch (adapter->ahw->post_mode) {
+       case QLC_83XX_POST_FAST_MODE:
+               timeout = QLC_83XX_POST_FAST_MODE_TIMEOUT + 2000;
+               break;
+       case QLC_83XX_POST_MEDIUM_MODE:
+               timeout = QLC_83XX_POST_MED_MODE_TIMEOUT + 2000;
+               break;
+       case QLC_83XX_POST_SLOW_MODE:
+               timeout = QLC_83XX_POST_SLOW_MODE_TIMEOUT + 2000;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       strncpy(fw_info->fw_file_name, QLC_83XX_POST_FW_FILE_NAME,
+               QLC_FW_FILE_NAME_LEN);
+
+       ret = request_firmware(&fw_info->fw, fw_info->fw_file_name, dev);
+       if (ret) {
+               dev_err(dev, "POST firmware can not be loaded, skipping POST\n");
+               return 0;
+       }
+
+       ret = qlcnic_83xx_copy_fw_file(adapter);
+       if (ret)
+               return ret;
+
+       /* clear QLC_83XX_POST_SIGNATURE_REG register */
+       qlcnic_ind_wr(adapter, QLC_83XX_POST_SIGNATURE_REG, 0);
+
+       /* Set POST mode */
+       qlcnic_ind_wr(adapter, QLC_83XX_POST_MODE_REG,
+                     adapter->ahw->post_mode);
+
+       QLC_SHARED_REG_WR32(adapter, QLCNIC_FW_IMG_VALID,
+                           QLC_83XX_BOOT_FROM_FILE);
+
+       qlcnic_83xx_start_hw(adapter);
+
+       count = 0;
+       do {
+               msleep(100);
+               count += 100;
+
+               signature = qlcnic_ind_rd(adapter, QLC_83XX_POST_SIGNATURE_REG);
+               if (signature == QLC_83XX_POST_PASS)
+                       break;
+       } while (timeout > count);
+
+       if (timeout <= count) {
+               dev_err(dev, "POST timed out, signature = 0x%08x\n", signature);
+               return -EIO;
+       }
+
+       switch (signature) {
+       case QLC_83XX_POST_PASS:
+               dev_info(dev, "POST passed, Signature = 0x%08x\n", signature);
+               break;
+       case QLC_83XX_POST_ASIC_STRESS_TEST_FAIL:
+               dev_err(dev, "POST failed, Test case : ASIC STRESS TEST, Signature = 0x%08x\n",
+                       signature);
+               ret = -EIO;
+               break;
+       case QLC_83XX_POST_DDR_TEST_FAIL:
+               dev_err(dev, "POST failed, Test case : DDT TEST, Signature = 0x%08x\n",
+                       signature);
+               ret = -EIO;
+               break;
+       case QLC_83XX_POST_ASIC_MEMORY_TEST_FAIL:
+               dev_err(dev, "POST failed, Test case : ASIC MEMORY TEST, Signature = 0x%08x\n",
+                       signature);
+               ret = -EIO;
+               break;
+       case QLC_83XX_POST_FLASH_TEST_FAIL:
+               dev_err(dev, "POST failed, Test case : FLASH TEST, Signature = 0x%08x\n",
+                       signature);
+               ret = -EIO;
+               break;
+       default:
+               dev_err(dev, "POST failed, Test case : INVALID, Signature = 0x%08x\n",
+                       signature);
+               ret = -EIO;
+               break;
+       }
+
+       return ret;
+}
+
 static int qlcnic_83xx_load_fw_image_from_host(struct qlcnic_adapter *adapter)
 {
        struct qlc_83xx_fw_info *fw_info = adapter->ahw->fw_info;
@@ -2104,8 +2234,27 @@ static int qlcnic_83xx_restart_hw(struct qlcnic_adapter *adapter)
 
        if (qlcnic_83xx_copy_bootloader(adapter))
                return err;
+
+       /* Check if POST needs to be run */
+       if (adapter->ahw->run_post) {
+               err = qlcnic_83xx_run_post(adapter);
+               if (err)
+                       return err;
+
+               /* No need to run POST in next reset sequence */
+               adapter->ahw->run_post = false;
+
+               /* Again reset the adapter to load regular firmware  */
+               qlcnic_83xx_stop_hw(adapter);
+               qlcnic_83xx_init_hw(adapter);
+
+               err = qlcnic_83xx_copy_bootloader(adapter);
+               if (err)
+                       return err;
+       }
+
        /* Boot either flash image or firmware image from host file system */
-       if (qlcnic_load_fw_file) {
+       if (qlcnic_load_fw_file == 1) {
                if (qlcnic_83xx_load_fw_image_from_host(adapter))
                        return err;
        } else {
@@ -2269,6 +2418,7 @@ static int qlcnic_83xx_get_fw_info(struct qlcnic_adapter *adapter)
                fw_info = ahw->fw_info;
                switch (pdev->device) {
                case PCI_DEVICE_ID_QLOGIC_QLE834X:
+               case PCI_DEVICE_ID_QLOGIC_QLE8830:
                        strncpy(fw_info->fw_file_name, QLC_83XX_FW_FILE_NAME,
                                QLC_FW_FILE_NAME_LEN);
                        break;
@@ -2313,6 +2463,25 @@ int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac)
        adapter->rx_mac_learn = false;
        ahw->msix_supported = !!qlcnic_use_msi_x;
 
+       /* Check if POST needs to be run */
+       switch (qlcnic_load_fw_file) {
+       case 2:
+               ahw->post_mode = QLC_83XX_POST_FAST_MODE;
+               ahw->run_post = true;
+               break;
+       case 3:
+               ahw->post_mode = QLC_83XX_POST_MEDIUM_MODE;
+               ahw->run_post = true;
+               break;
+       case 4:
+               ahw->post_mode = QLC_83XX_POST_SLOW_MODE;
+               ahw->run_post = true;
+               break;
+       default:
+               ahw->run_post = false;
+               break;
+       }
+
        qlcnic_83xx_init_rings(adapter);
 
        err = qlcnic_83xx_init_mailbox_work(adapter);
index 851cb4a80d50a6d4b2733ac2693fd799cca37885..8102673cb37f6931fd16f26d70357a594ef831ad 100644 (file)
@@ -341,7 +341,7 @@ qlcnic_pcie_sem_lock(struct qlcnic_adapter *adapter, int sem, u32 id_reg)
                        }
                        return -EIO;
                }
-               msleep(1);
+               usleep_range(1000, 1500);
        }
 
        if (id_reg)
index c4262c23ed7c77b009f6c5cebf233a54ebfd685b..be41e4c77b657285841c610c1f30a701dc2c87ee 100644 (file)
@@ -537,7 +537,7 @@ int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter)
        QLCWR32(adapter, QLCNIC_CRB_PEG_NET_3 + 0xc, 0);
        QLCWR32(adapter, QLCNIC_CRB_PEG_NET_4 + 0x8, 0);
        QLCWR32(adapter, QLCNIC_CRB_PEG_NET_4 + 0xc, 0);
-       msleep(1);
+       usleep_range(1000, 1500);
 
        QLC_SHARED_REG_WR32(adapter, QLCNIC_PEG_HALT_STATUS1, 0);
        QLC_SHARED_REG_WR32(adapter, QLCNIC_PEG_HALT_STATUS2, 0);
@@ -1198,7 +1198,7 @@ qlcnic_load_firmware(struct qlcnic_adapter *adapter)
                        flashaddr += 8;
                }
        }
-       msleep(1);
+       usleep_range(1000, 1500);
 
        QLCWR32(adapter, QLCNIC_CRB_PEG_NET_0 + 0x18, 0x1020);
        QLCWR32(adapter, QLCNIC_ROMUSB_GLB_SW_RESET, 0x80001e);
@@ -1295,7 +1295,7 @@ next:
                rc = qlcnic_validate_firmware(adapter);
                if (rc != 0) {
                        release_firmware(adapter->fw);
-                       msleep(1);
+                       usleep_range(1000, 1500);
                        goto next;
                }
        }
index e45bf09af0c9fe4dbe9cdc629370af792ab88c01..18e5de72e9b4c2c9b95848bf444597251942039e 100644 (file)
@@ -1753,7 +1753,7 @@ qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter,
 
        if (qlcnic_encap_length(sts_data[1]) &&
            skb->ip_summed == CHECKSUM_UNNECESSARY) {
-               skb->encapsulation = 1;
+               skb->csum_level = 1;
                adapter->stats.encap_rx_csummed++;
        }
 
index cf08b2de071e4d602745d2dd5c7bc6e7b3b530df..f5e29f7bdae39b77eed8abc0b8e73360ceeda698 100644 (file)
@@ -52,7 +52,7 @@ MODULE_PARM_DESC(auto_fw_reset, "Auto firmware reset (0=disabled, 1=enabled)");
 module_param_named(auto_fw_reset, qlcnic_auto_fw_reset, int, 0644);
 
 int qlcnic_load_fw_file;
-MODULE_PARM_DESC(load_fw_file, "Load firmware from (0=flash, 1=file)");
+MODULE_PARM_DESC(load_fw_file, "Load firmware from (0=flash, 1=file, 2=POST in fast mode, 3= POST in medium mode, 4=POST in slow mode)");
 module_param_named(load_fw_file, qlcnic_load_fw_file, int, 0444);
 
 static int qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
@@ -111,6 +111,7 @@ static u32 qlcnic_vlan_tx_check(struct qlcnic_adapter *adapter)
 static const struct pci_device_id qlcnic_pci_tbl[] = {
        ENTRY(PCI_DEVICE_ID_QLOGIC_QLE824X),
        ENTRY(PCI_DEVICE_ID_QLOGIC_QLE834X),
+       ENTRY(PCI_DEVICE_ID_QLOGIC_QLE8830),
        ENTRY(PCI_DEVICE_ID_QLOGIC_VF_QLE834X),
        ENTRY(PCI_DEVICE_ID_QLOGIC_QLE844X),
        ENTRY(PCI_DEVICE_ID_QLOGIC_VF_QLE844X),
@@ -227,6 +228,11 @@ static const struct qlcnic_board_info qlcnic_boards[] = {
        { PCI_VENDOR_ID_QLOGIC,
          PCI_DEVICE_ID_QLOGIC_QLE834X,
          0x0, 0x0, "8300 Series 1/10GbE Controller" },
+       { PCI_VENDOR_ID_QLOGIC,
+         PCI_DEVICE_ID_QLOGIC_QLE8830,
+         0x0,
+         0x0,
+         "8830 Series 1/10GbE Controller" },
        { PCI_VENDOR_ID_QLOGIC,
          PCI_DEVICE_ID_QLOGIC_QLE824X,
          PCI_VENDOR_ID_QLOGIC,
@@ -1131,6 +1137,7 @@ static void qlcnic_get_bar_length(u32 dev_id, ulong *bar)
                *bar = QLCNIC_82XX_BAR0_LENGTH;
                break;
        case PCI_DEVICE_ID_QLOGIC_QLE834X:
+       case PCI_DEVICE_ID_QLOGIC_QLE8830:
        case PCI_DEVICE_ID_QLOGIC_QLE844X:
        case PCI_DEVICE_ID_QLOGIC_VF_QLE834X:
        case PCI_DEVICE_ID_QLOGIC_VF_QLE844X:
@@ -2474,6 +2481,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                ahw->reg_tbl = (u32 *) qlcnic_reg_tbl;
                break;
        case PCI_DEVICE_ID_QLOGIC_QLE834X:
+       case PCI_DEVICE_ID_QLOGIC_QLE8830:
        case PCI_DEVICE_ID_QLOGIC_QLE844X:
                qlcnic_83xx_register_map(ahw);
                break;
index e46fc39d425d45ee1d0d081b45954801c46f89ed..c9f57fb84b9eb47215f0cc21a680dce46d253e56 100644 (file)
@@ -47,15 +47,26 @@ struct qlcnic_common_entry_hdr {
        u32     type;
        u32     offset;
        u32     cap_size;
+#if defined(__LITTLE_ENDIAN)
        u8      mask;
        u8      rsvd[2];
        u8      flags;
+#else
+       u8      flags;
+       u8      rsvd[2];
+       u8      mask;
+#endif
 } __packed;
 
 struct __crb {
        u32     addr;
+#if defined(__LITTLE_ENDIAN)
        u8      stride;
        u8      rsvd1[3];
+#else
+       u8      rsvd1[3];
+       u8      stride;
+#endif
        u32     data_size;
        u32     no_ops;
        u32     rsvd2[4];
@@ -63,15 +74,28 @@ struct __crb {
 
 struct __ctrl {
        u32     addr;
+#if defined(__LITTLE_ENDIAN)
        u8      stride;
        u8      index_a;
        u16     timeout;
+#else
+       u16     timeout;
+       u8      index_a;
+       u8      stride;
+#endif
        u32     data_size;
        u32     no_ops;
+#if defined(__LITTLE_ENDIAN)
        u8      opcode;
        u8      index_v;
        u8      shl_val;
        u8      shr_val;
+#else
+       u8      shr_val;
+       u8      shl_val;
+       u8      index_v;
+       u8      opcode;
+#endif
        u32     val1;
        u32     val2;
        u32     val3;
@@ -79,16 +103,27 @@ struct __ctrl {
 
 struct __cache {
        u32     addr;
+#if defined(__LITTLE_ENDIAN)
        u16     stride;
        u16     init_tag_val;
+#else
+       u16     init_tag_val;
+       u16     stride;
+#endif
        u32     size;
        u32     no_ops;
        u32     ctrl_addr;
        u32     ctrl_val;
        u32     read_addr;
+#if defined(__LITTLE_ENDIAN)
        u8      read_addr_stride;
        u8      read_addr_num;
        u8      rsvd1[2];
+#else
+       u8      rsvd1[2];
+       u8      read_addr_num;
+       u8      read_addr_stride;
+#endif
 } __packed;
 
 struct __ocm {
@@ -122,23 +157,39 @@ struct __mux {
 
 struct __queue {
        u32     sel_addr;
+#if defined(__LITTLE_ENDIAN)
        u16     stride;
        u8      rsvd[2];
+#else
+       u8      rsvd[2];
+       u16     stride;
+#endif
        u32     size;
        u32     no_ops;
        u8      rsvd2[8];
        u32     read_addr;
+#if defined(__LITTLE_ENDIAN)
        u8      read_addr_stride;
        u8      read_addr_cnt;
        u8      rsvd3[2];
+#else
+       u8      rsvd3[2];
+       u8      read_addr_cnt;
+       u8      read_addr_stride;
+#endif
 } __packed;
 
 struct __pollrd {
        u32     sel_addr;
        u32     read_addr;
        u32     sel_val;
+#if defined(__LITTLE_ENDIAN)
        u16     sel_val_stride;
        u16     no_ops;
+#else
+       u16     no_ops;
+       u16     sel_val_stride;
+#endif
        u32     poll_wait;
        u32     poll_mask;
        u32     data_size;
@@ -153,9 +204,15 @@ struct __mux2 {
        u32     no_ops;
        u32     sel_val_mask;
        u32     read_addr;
+#if defined(__LITTLE_ENDIAN)
        u8      sel_val_stride;
        u8      data_size;
        u8      rsvd[2];
+#else
+       u8      rsvd[2];
+       u8      data_size;
+       u8      sel_val_stride;
+#endif
 } __packed;
 
 struct __pollrdmwr {
index f5786d5792df06fe16db6f7ffd2276f9bdabe96f..59a721fba018249679bf15d0984b90e4835c155e 100644 (file)
@@ -280,6 +280,7 @@ static ssize_t qlcnic_sysfs_read_crb(struct file *filp, struct kobject *kobj,
        if (ret != 0)
                return ret;
        qlcnic_read_crb(adapter, buf, offset, size);
+       qlcnic_swap32_buffer((u32 *)buf, size / sizeof(u32));
 
        return size;
 }
@@ -296,6 +297,7 @@ static ssize_t qlcnic_sysfs_write_crb(struct file *filp, struct kobject *kobj,
        if (ret != 0)
                return ret;
 
+       qlcnic_swap32_buffer((u32 *)buf, size / sizeof(u32));
        qlcnic_write_crb(adapter, buf, offset, size);
        return size;
 }
@@ -329,6 +331,7 @@ static ssize_t qlcnic_sysfs_read_mem(struct file *filp, struct kobject *kobj,
                return -EIO;
 
        memcpy(buf, &data, size);
+       qlcnic_swap32_buffer((u32 *)buf, size / sizeof(u32));
 
        return size;
 }
@@ -346,6 +349,7 @@ static ssize_t qlcnic_sysfs_write_mem(struct file *filp, struct kobject *kobj,
        if (ret != 0)
                return ret;
 
+       qlcnic_swap32_buffer((u32 *)buf, size / sizeof(u32));
        memcpy(&data, buf, size);
 
        if (qlcnic_pci_mem_write_2M(adapter, offset, data))
@@ -412,6 +416,7 @@ static ssize_t qlcnic_sysfs_write_pm_config(struct file *filp,
        if (rem)
                return QL_STATUS_INVALID_PARAM;
 
+       qlcnic_swap32_buffer((u32 *)buf, size / sizeof(u32));
        pm_cfg = (struct qlcnic_pm_func_cfg *)buf;
        ret = validate_pm_config(adapter, pm_cfg, count);
 
@@ -474,6 +479,7 @@ static ssize_t qlcnic_sysfs_read_pm_config(struct file *filp,
                pm_cfg[pci_func].dest_npar = 0;
                pm_cfg[pci_func].pci_func = i;
        }
+       qlcnic_swap32_buffer((u32 *)buf, size / sizeof(u32));
        return size;
 }
 
@@ -555,6 +561,7 @@ static ssize_t qlcnic_sysfs_write_esw_config(struct file *file,
        if (rem)
                return QL_STATUS_INVALID_PARAM;
 
+       qlcnic_swap32_buffer((u32 *)buf, size / sizeof(u32));
        esw_cfg = (struct qlcnic_esw_func_cfg *)buf;
        ret = validate_esw_config(adapter, esw_cfg, count);
        if (ret)
@@ -649,6 +656,7 @@ static ssize_t qlcnic_sysfs_read_esw_config(struct file *file,
                if (qlcnic_get_eswitch_port_config(adapter, &esw_cfg[pci_func]))
                        return QL_STATUS_INVALID_PARAM;
        }
+       qlcnic_swap32_buffer((u32 *)buf, size / sizeof(u32));
        return size;
 }
 
@@ -688,6 +696,7 @@ static ssize_t qlcnic_sysfs_write_npar_config(struct file *file,
        if (rem)
                return QL_STATUS_INVALID_PARAM;
 
+       qlcnic_swap32_buffer((u32 *)buf, size / sizeof(u32));
        np_cfg = (struct qlcnic_npar_func_cfg *)buf;
        ret = validate_npar_config(adapter, np_cfg, count);
        if (ret)
@@ -759,6 +768,7 @@ static ssize_t qlcnic_sysfs_read_npar_config(struct file *file,
                np_cfg[pci_func].max_tx_queues = nic_info.max_tx_ques;
                np_cfg[pci_func].max_rx_queues = nic_info.max_rx_ques;
        }
+       qlcnic_swap32_buffer((u32 *)buf, size / sizeof(u32));
        return size;
 }
 
@@ -916,6 +926,7 @@ static ssize_t qlcnic_sysfs_read_pci_config(struct file *file,
 
        pci_cfg = (struct qlcnic_pci_func_cfg *)buf;
        count = size / sizeof(struct qlcnic_pci_func_cfg);
+       qlcnic_swap32_buffer((u32 *)pci_info, size / sizeof(u32));
        for (i = 0; i < count; i++) {
                pci_cfg[i].pci_func = pci_info[i].id;
                pci_cfg[i].func_type = pci_info[i].type;
@@ -969,6 +980,7 @@ static ssize_t qlcnic_83xx_sysfs_flash_read_handler(struct file *filp,
        }
 
        qlcnic_83xx_unlock_flash(adapter);
+       qlcnic_swap32_buffer((u32 *)p_read_buf, count);
        memcpy(buf, p_read_buf, size);
        kfree(p_read_buf);
 
@@ -986,9 +998,10 @@ static int qlcnic_83xx_sysfs_flash_bulk_write(struct qlcnic_adapter *adapter,
        if (!p_cache)
                return -ENOMEM;
 
+       count = size / sizeof(u32);
+       qlcnic_swap32_buffer((u32 *)buf, count);
        memcpy(p_cache, buf, size);
        p_src = p_cache;
-       count = size / sizeof(u32);
 
        if (qlcnic_83xx_lock_flash(adapter) != 0) {
                kfree(p_cache);
@@ -1053,6 +1066,7 @@ static int qlcnic_83xx_sysfs_flash_write(struct qlcnic_adapter *adapter,
        if (!p_cache)
                return -ENOMEM;
 
+       qlcnic_swap32_buffer((u32 *)buf, size / sizeof(u32));
        memcpy(p_cache, buf, size);
        p_src = p_cache;
        count = size / sizeof(u32);
index 188626e2a861d317510617dce742595b88bd3abd..3e96f269150d197253fdcdf3066c1a2da5b62985 100644 (file)
@@ -2556,6 +2556,7 @@ static int ql_tso(struct sk_buff *skb, struct ob_mac_tso_iocb_req *mac_iocb_ptr)
 
        if (skb_is_gso(skb)) {
                int err;
+               __be16 l3_proto = vlan_get_protocol(skb);
 
                err = skb_cow_head(skb, 0);
                if (err < 0)
@@ -2572,7 +2573,7 @@ static int ql_tso(struct sk_buff *skb, struct ob_mac_tso_iocb_req *mac_iocb_ptr)
                                << OB_MAC_TRANSPORT_HDR_SHIFT);
                mac_iocb_ptr->mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
                mac_iocb_ptr->flags2 |= OB_MAC_TSO_IOCB_LSO;
-               if (likely(skb->protocol == htons(ETH_P_IP))) {
+               if (likely(l3_proto == htons(ETH_P_IP))) {
                        struct iphdr *iph = ip_hdr(skb);
                        iph->check = 0;
                        mac_iocb_ptr->flags1 |= OB_MAC_TSO_IOCB_IP4;
@@ -2580,7 +2581,7 @@ static int ql_tso(struct sk_buff *skb, struct ob_mac_tso_iocb_req *mac_iocb_ptr)
                                                                 iph->daddr, 0,
                                                                 IPPROTO_TCP,
                                                                 0);
-               } else if (skb->protocol == htons(ETH_P_IPV6)) {
+               } else if (l3_proto == htons(ETH_P_IPV6)) {
                        mac_iocb_ptr->flags1 |= OB_MAC_TSO_IOCB_IP6;
                        tcp_hdr(skb)->check =
                            ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
index 91652e7235e469be8c20a7ecd7a5b926178ab1af..02dd92ac1764cbe87195dcb6fa8d018450dc728b 100644 (file)
 #define FIRMWARE_8106E_2       "rtl_nic/rtl8106e-2.fw"
 #define FIRMWARE_8168G_2       "rtl_nic/rtl8168g-2.fw"
 #define FIRMWARE_8168G_3       "rtl_nic/rtl8168g-3.fw"
+#define FIRMWARE_8168H_1       "rtl_nic/rtl8168h-1.fw"
+#define FIRMWARE_8168H_2       "rtl_nic/rtl8168h-2.fw"
+#define FIRMWARE_8107E_1       "rtl_nic/rtl8107e-1.fw"
+#define FIRMWARE_8107E_2       "rtl_nic/rtl8107e-2.fw"
 
 #ifdef RTL8169_DEBUG
 #define assert(expr) \
@@ -147,6 +151,10 @@ enum mac_version {
        RTL_GIGA_MAC_VER_42,
        RTL_GIGA_MAC_VER_43,
        RTL_GIGA_MAC_VER_44,
+       RTL_GIGA_MAC_VER_45,
+       RTL_GIGA_MAC_VER_46,
+       RTL_GIGA_MAC_VER_47,
+       RTL_GIGA_MAC_VER_48,
        RTL_GIGA_MAC_NONE   = 0xff,
 };
 
@@ -282,6 +290,18 @@ static const struct {
        [RTL_GIGA_MAC_VER_44] =
                _R("RTL8411",           RTL_TD_1, FIRMWARE_8411_2,
                                                        JUMBO_9K, false),
+       [RTL_GIGA_MAC_VER_45] =
+               _R("RTL8168h/8111h",    RTL_TD_1, FIRMWARE_8168H_1,
+                                                       JUMBO_9K, false),
+       [RTL_GIGA_MAC_VER_46] =
+               _R("RTL8168h/8111h",    RTL_TD_1, FIRMWARE_8168H_2,
+                                                       JUMBO_9K, false),
+       [RTL_GIGA_MAC_VER_47] =
+               _R("RTL8107e",          RTL_TD_1, FIRMWARE_8107E_1,
+                                                       JUMBO_1K, false),
+       [RTL_GIGA_MAC_VER_48] =
+               _R("RTL8107e",          RTL_TD_1, FIRMWARE_8107E_2,
+                                                       JUMBO_1K, false),
 };
 #undef _R
 
@@ -410,6 +430,7 @@ enum rtl8168_8101_registers {
 #define        EPHYAR_DATA_MASK                0xffff
        DLLPR                   = 0xd0,
 #define        PFM_EN                          (1 << 6)
+#define        TX_10M_PS_EN                    (1 << 7)
        DBG_REG                 = 0xd1,
 #define        FIX_NAK_1                       (1 << 4)
 #define        FIX_NAK_2                       (1 << 3)
@@ -429,6 +450,8 @@ enum rtl8168_8101_registers {
 #define        EFUSEAR_REG_MASK                0x03ff
 #define        EFUSEAR_REG_SHIFT               8
 #define        EFUSEAR_DATA_MASK               0xff
+       MISC_1                  = 0xf2,
+#define        PFM_D3COLD_EN                   (1 << 6)
 };
 
 enum rtl8168_registers {
@@ -447,6 +470,7 @@ enum rtl8168_registers {
 #define ERIAR_MASK_SHIFT               12
 #define ERIAR_MASK_0001                        (0x1 << ERIAR_MASK_SHIFT)
 #define ERIAR_MASK_0011                        (0x3 << ERIAR_MASK_SHIFT)
+#define ERIAR_MASK_0100                        (0x4 << ERIAR_MASK_SHIFT)
 #define ERIAR_MASK_0101                        (0x5 << ERIAR_MASK_SHIFT)
 #define ERIAR_MASK_1111                        (0xf << ERIAR_MASK_SHIFT)
        EPHY_RXER_NUM           = 0x7c,
@@ -598,6 +622,9 @@ enum rtl_register_content {
 
        /* DumpCounterCommand */
        CounterDump     = 0x8,
+
+       /* magic enable v2 */
+       MagicPacket_v2  = (1 << 16),    /* Wake up when receives a Magic Packet */
 };
 
 enum rtl_desc_bit {
@@ -823,6 +850,10 @@ MODULE_FIRMWARE(FIRMWARE_8106E_1);
 MODULE_FIRMWARE(FIRMWARE_8106E_2);
 MODULE_FIRMWARE(FIRMWARE_8168G_2);
 MODULE_FIRMWARE(FIRMWARE_8168G_3);
+MODULE_FIRMWARE(FIRMWARE_8168H_1);
+MODULE_FIRMWARE(FIRMWARE_8168H_2);
+MODULE_FIRMWARE(FIRMWARE_8107E_1);
+MODULE_FIRMWARE(FIRMWARE_8107E_2);
 
 static void rtl_lock_work(struct rtl8169_private *tp)
 {
@@ -1514,8 +1545,17 @@ static u32 __rtl8169_get_wol(struct rtl8169_private *tp)
        options = RTL_R8(Config3);
        if (options & LinkUp)
                wolopts |= WAKE_PHY;
-       if (options & MagicPacket)
-               wolopts |= WAKE_MAGIC;
+       switch (tp->mac_version) {
+       case RTL_GIGA_MAC_VER_45:
+       case RTL_GIGA_MAC_VER_46:
+               if (rtl_eri_read(tp, 0xdc, ERIAR_EXGMAC) & MagicPacket_v2)
+                       wolopts |= WAKE_MAGIC;
+               break;
+       default:
+               if (options & MagicPacket)
+                       wolopts |= WAKE_MAGIC;
+               break;
+       }
 
        options = RTL_R8(Config5);
        if (options & UWF)
@@ -1543,24 +1583,48 @@ static void rtl8169_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts)
 {
        void __iomem *ioaddr = tp->mmio_addr;
-       unsigned int i;
+       unsigned int i, tmp;
        static const struct {
                u32 opt;
                u16 reg;
                u8  mask;
        } cfg[] = {
                { WAKE_PHY,   Config3, LinkUp },
-               { WAKE_MAGIC, Config3, MagicPacket },
                { WAKE_UCAST, Config5, UWF },
                { WAKE_BCAST, Config5, BWF },
                { WAKE_MCAST, Config5, MWF },
-               { WAKE_ANY,   Config5, LanWake }
+               { WAKE_ANY,   Config5, LanWake },
+               { WAKE_MAGIC, Config3, MagicPacket }
        };
        u8 options;
 
        RTL_W8(Cfg9346, Cfg9346_Unlock);
 
-       for (i = 0; i < ARRAY_SIZE(cfg); i++) {
+       switch (tp->mac_version) {
+       case RTL_GIGA_MAC_VER_45:
+       case RTL_GIGA_MAC_VER_46:
+               tmp = ARRAY_SIZE(cfg) - 1;
+               if (wolopts & WAKE_MAGIC)
+                       rtl_w1w0_eri(tp,
+                                    0x0dc,
+                                    ERIAR_MASK_0100,
+                                    MagicPacket_v2,
+                                    0x0000,
+                                    ERIAR_EXGMAC);
+               else
+                       rtl_w1w0_eri(tp,
+                                    0x0dc,
+                                    ERIAR_MASK_0100,
+                                    0x0000,
+                                    MagicPacket_v2,
+                                    ERIAR_EXGMAC);
+               break;
+       default:
+               tmp = ARRAY_SIZE(cfg);
+               break;
+       }
+
+       for (i = 0; i < tmp; i++) {
                options = RTL_R8(cfg[i].reg) & ~cfg[i].mask;
                if (wolopts & cfg[i].opt)
                        options |= cfg[i].mask;
@@ -2044,6 +2108,10 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp,
                u32 val;
                int mac_version;
        } mac_info[] = {
+               /* 8168H family. */
+               { 0x7cf00000, 0x54100000,       RTL_GIGA_MAC_VER_46 },
+               { 0x7cf00000, 0x54000000,       RTL_GIGA_MAC_VER_45 },
+
                /* 8168G family. */
                { 0x7cf00000, 0x5c800000,       RTL_GIGA_MAC_VER_44 },
                { 0x7cf00000, 0x50900000,       RTL_GIGA_MAC_VER_42 },
@@ -2139,6 +2207,14 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp,
                tp->mac_version = tp->mii.supports_gmii ?
                                  RTL_GIGA_MAC_VER_42 :
                                  RTL_GIGA_MAC_VER_43;
+       } else if (tp->mac_version == RTL_GIGA_MAC_VER_45) {
+               tp->mac_version = tp->mii.supports_gmii ?
+                                 RTL_GIGA_MAC_VER_45 :
+                                 RTL_GIGA_MAC_VER_47;
+       } else if (tp->mac_version == RTL_GIGA_MAC_VER_46) {
+               tp->mac_version = tp->mii.supports_gmii ?
+                                 RTL_GIGA_MAC_VER_46 :
+                                 RTL_GIGA_MAC_VER_48;
        }
 }
 
@@ -3464,6 +3540,189 @@ static void rtl8168g_2_hw_phy_config(struct rtl8169_private *tp)
        rtl_apply_firmware(tp);
 }
 
+static void rtl8168h_1_hw_phy_config(struct rtl8169_private *tp)
+{
+       u16 dout_tapbin;
+       u32 data;
+
+       rtl_apply_firmware(tp);
+
+       /* CHN EST parameters adjust - giga master */
+       rtl_writephy(tp, 0x1f, 0x0a43);
+       rtl_writephy(tp, 0x13, 0x809b);
+       rtl_w1w0_phy(tp, 0x14, 0x8000, 0xf800);
+       rtl_writephy(tp, 0x13, 0x80a2);
+       rtl_w1w0_phy(tp, 0x14, 0x8000, 0xff00);
+       rtl_writephy(tp, 0x13, 0x80a4);
+       rtl_w1w0_phy(tp, 0x14, 0x8500, 0xff00);
+       rtl_writephy(tp, 0x13, 0x809c);
+       rtl_w1w0_phy(tp, 0x14, 0xbd00, 0xff00);
+       rtl_writephy(tp, 0x1f, 0x0000);
+
+       /* CHN EST parameters adjust - giga slave */
+       rtl_writephy(tp, 0x1f, 0x0a43);
+       rtl_writephy(tp, 0x13, 0x80ad);
+       rtl_w1w0_phy(tp, 0x14, 0x7000, 0xf800);
+       rtl_writephy(tp, 0x13, 0x80b4);
+       rtl_w1w0_phy(tp, 0x14, 0x5000, 0xff00);
+       rtl_writephy(tp, 0x13, 0x80ac);
+       rtl_w1w0_phy(tp, 0x14, 0x4000, 0xff00);
+       rtl_writephy(tp, 0x1f, 0x0000);
+
+       /* CHN EST parameters adjust - fnet */
+       rtl_writephy(tp, 0x1f, 0x0a43);
+       rtl_writephy(tp, 0x13, 0x808e);
+       rtl_w1w0_phy(tp, 0x14, 0x1200, 0xff00);
+       rtl_writephy(tp, 0x13, 0x8090);
+       rtl_w1w0_phy(tp, 0x14, 0xe500, 0xff00);
+       rtl_writephy(tp, 0x13, 0x8092);
+       rtl_w1w0_phy(tp, 0x14, 0x9f00, 0xff00);
+       rtl_writephy(tp, 0x1f, 0x0000);
+
+       /* enable R-tune & PGA-retune function */
+       dout_tapbin = 0;
+       rtl_writephy(tp, 0x1f, 0x0a46);
+       data = rtl_readphy(tp, 0x13);
+       data &= 3;
+       data <<= 2;
+       dout_tapbin |= data;
+       data = rtl_readphy(tp, 0x12);
+       data &= 0xc000;
+       data >>= 14;
+       dout_tapbin |= data;
+       dout_tapbin = ~(dout_tapbin^0x08);
+       dout_tapbin <<= 12;
+       dout_tapbin &= 0xf000;
+       rtl_writephy(tp, 0x1f, 0x0a43);
+       rtl_writephy(tp, 0x13, 0x827a);
+       rtl_w1w0_phy(tp, 0x14, dout_tapbin, 0xf000);
+       rtl_writephy(tp, 0x13, 0x827b);
+       rtl_w1w0_phy(tp, 0x14, dout_tapbin, 0xf000);
+       rtl_writephy(tp, 0x13, 0x827c);
+       rtl_w1w0_phy(tp, 0x14, dout_tapbin, 0xf000);
+       rtl_writephy(tp, 0x13, 0x827d);
+       rtl_w1w0_phy(tp, 0x14, dout_tapbin, 0xf000);
+
+       rtl_writephy(tp, 0x1f, 0x0a43);
+       rtl_writephy(tp, 0x13, 0x0811);
+       rtl_w1w0_phy(tp, 0x14, 0x0800, 0x0000);
+       rtl_writephy(tp, 0x1f, 0x0a42);
+       rtl_w1w0_phy(tp, 0x16, 0x0002, 0x0000);
+       rtl_writephy(tp, 0x1f, 0x0000);
+
+       /* enable GPHY 10M */
+       rtl_writephy(tp, 0x1f, 0x0a44);
+       rtl_w1w0_phy(tp, 0x11, 0x0800, 0x0000);
+       rtl_writephy(tp, 0x1f, 0x0000);
+
+       /* SAR ADC performance */
+       rtl_writephy(tp, 0x1f, 0x0bca);
+       rtl_w1w0_phy(tp, 0x17, 0x4000, 0x3000);
+       rtl_writephy(tp, 0x1f, 0x0000);
+
+       rtl_writephy(tp, 0x1f, 0x0a43);
+       rtl_writephy(tp, 0x13, 0x803f);
+       rtl_w1w0_phy(tp, 0x14, 0x0000, 0x3000);
+       rtl_writephy(tp, 0x13, 0x8047);
+       rtl_w1w0_phy(tp, 0x14, 0x0000, 0x3000);
+       rtl_writephy(tp, 0x13, 0x804f);
+       rtl_w1w0_phy(tp, 0x14, 0x0000, 0x3000);
+       rtl_writephy(tp, 0x13, 0x8057);
+       rtl_w1w0_phy(tp, 0x14, 0x0000, 0x3000);
+       rtl_writephy(tp, 0x13, 0x805f);
+       rtl_w1w0_phy(tp, 0x14, 0x0000, 0x3000);
+       rtl_writephy(tp, 0x13, 0x8067);
+       rtl_w1w0_phy(tp, 0x14, 0x0000, 0x3000);
+       rtl_writephy(tp, 0x13, 0x806f);
+       rtl_w1w0_phy(tp, 0x14, 0x0000, 0x3000);
+       rtl_writephy(tp, 0x1f, 0x0000);
+
+       /* disable phy pfm mode */
+       rtl_writephy(tp, 0x1f, 0x0a44);
+       rtl_w1w0_phy(tp, 0x14, 0x0000, 0x0080);
+       rtl_writephy(tp, 0x1f, 0x0000);
+
+       /* Check ALDPS bit, disable it if enabled */
+       rtl_writephy(tp, 0x1f, 0x0a43);
+       if (rtl_readphy(tp, 0x10) & 0x0004)
+               rtl_w1w0_phy(tp, 0x10, 0x0000, 0x0004);
+
+       rtl_writephy(tp, 0x1f, 0x0000);
+}
+
+static void rtl8168h_2_hw_phy_config(struct rtl8169_private *tp)
+{
+       u16 ioffset_p3, ioffset_p2, ioffset_p1, ioffset_p0;
+       u16 rlen;
+       u32 data;
+
+       rtl_apply_firmware(tp);
+
+       /* CHIN EST parameter update */
+       rtl_writephy(tp, 0x1f, 0x0a43);
+       rtl_writephy(tp, 0x13, 0x808a);
+       rtl_w1w0_phy(tp, 0x14, 0x000a, 0x003f);
+       rtl_writephy(tp, 0x1f, 0x0000);
+
+       /* enable R-tune & PGA-retune function */
+       rtl_writephy(tp, 0x1f, 0x0a43);
+       rtl_writephy(tp, 0x13, 0x0811);
+       rtl_w1w0_phy(tp, 0x14, 0x0800, 0x0000);
+       rtl_writephy(tp, 0x1f, 0x0a42);
+       rtl_w1w0_phy(tp, 0x16, 0x0002, 0x0000);
+       rtl_writephy(tp, 0x1f, 0x0000);
+
+       /* enable GPHY 10M */
+       rtl_writephy(tp, 0x1f, 0x0a44);
+       rtl_w1w0_phy(tp, 0x11, 0x0800, 0x0000);
+       rtl_writephy(tp, 0x1f, 0x0000);
+
+       r8168_mac_ocp_write(tp, 0xdd02, 0x807d);
+       data = r8168_mac_ocp_read(tp, 0xdd02);
+       ioffset_p3 = ((data & 0x80)>>7);
+       ioffset_p3 <<= 3;
+
+       data = r8168_mac_ocp_read(tp, 0xdd00);
+       ioffset_p3 |= ((data & (0xe000))>>13);
+       ioffset_p2 = ((data & (0x1e00))>>9);
+       ioffset_p1 = ((data & (0x01e0))>>5);
+       ioffset_p0 = ((data & 0x0010)>>4);
+       ioffset_p0 <<= 3;
+       ioffset_p0 |= (data & (0x07));
+       data = (ioffset_p3<<12)|(ioffset_p2<<8)|(ioffset_p1<<4)|(ioffset_p0);
+
+       if ((ioffset_p3 != 0x0F) || (ioffset_p2 != 0x0F) ||
+           (ioffset_p1 != 0x0F) || (ioffset_p0 == 0x0F)) {
+               rtl_writephy(tp, 0x1f, 0x0bcf);
+               rtl_writephy(tp, 0x16, data);
+               rtl_writephy(tp, 0x1f, 0x0000);
+       }
+
+       /* Modify rlen (TX LPF corner frequency) level */
+       rtl_writephy(tp, 0x1f, 0x0bcd);
+       data = rtl_readphy(tp, 0x16);
+       data &= 0x000f;
+       rlen = 0;
+       if (data > 3)
+               rlen = data - 3;
+       data = rlen | (rlen<<4) | (rlen<<8) | (rlen<<12);
+       rtl_writephy(tp, 0x17, data);
+       rtl_writephy(tp, 0x1f, 0x0bcd);
+       rtl_writephy(tp, 0x1f, 0x0000);
+
+       /* disable phy pfm mode */
+       rtl_writephy(tp, 0x1f, 0x0a44);
+       rtl_w1w0_phy(tp, 0x14, 0x0000, 0x0080);
+       rtl_writephy(tp, 0x1f, 0x0000);
+
+       /* Check ALDPS bit, disable it if enabled */
+       rtl_writephy(tp, 0x1f, 0x0a43);
+       if (rtl_readphy(tp, 0x10) & 0x0004)
+               rtl_w1w0_phy(tp, 0x10, 0x0000, 0x0004);
+
+       rtl_writephy(tp, 0x1f, 0x0000);
+}
+
 static void rtl8102e_hw_phy_config(struct rtl8169_private *tp)
 {
        static const struct phy_reg phy_reg_init[] = {
@@ -3654,6 +3913,14 @@ static void rtl_hw_phy_config(struct net_device *dev)
        case RTL_GIGA_MAC_VER_44:
                rtl8168g_2_hw_phy_config(tp);
                break;
+       case RTL_GIGA_MAC_VER_45:
+       case RTL_GIGA_MAC_VER_47:
+               rtl8168h_1_hw_phy_config(tp);
+               break;
+       case RTL_GIGA_MAC_VER_46:
+       case RTL_GIGA_MAC_VER_48:
+               rtl8168h_2_hw_phy_config(tp);
+               break;
 
        case RTL_GIGA_MAC_VER_41:
        default:
@@ -3865,6 +4132,10 @@ static void rtl_init_mdio_ops(struct rtl8169_private *tp)
        case RTL_GIGA_MAC_VER_42:
        case RTL_GIGA_MAC_VER_43:
        case RTL_GIGA_MAC_VER_44:
+       case RTL_GIGA_MAC_VER_45:
+       case RTL_GIGA_MAC_VER_46:
+       case RTL_GIGA_MAC_VER_47:
+       case RTL_GIGA_MAC_VER_48:
                ops->write      = r8168g_mdio_write;
                ops->read       = r8168g_mdio_read;
                break;
@@ -3919,6 +4190,10 @@ static void rtl_wol_suspend_quirk(struct rtl8169_private *tp)
        case RTL_GIGA_MAC_VER_42:
        case RTL_GIGA_MAC_VER_43:
        case RTL_GIGA_MAC_VER_44:
+       case RTL_GIGA_MAC_VER_45:
+       case RTL_GIGA_MAC_VER_46:
+       case RTL_GIGA_MAC_VER_47:
+       case RTL_GIGA_MAC_VER_48:
                RTL_W32(RxConfig, RTL_R32(RxConfig) |
                        AcceptBroadcast | AcceptMulticast | AcceptMyPhys);
                break;
@@ -3987,6 +4262,10 @@ static void r810x_pll_power_up(struct rtl8169_private *tp)
        case RTL_GIGA_MAC_VER_13:
        case RTL_GIGA_MAC_VER_16:
                break;
+       case RTL_GIGA_MAC_VER_47:
+       case RTL_GIGA_MAC_VER_48:
+               RTL_W8(PMCH, RTL_R8(PMCH) | 0xC0);
+               break;
        default:
                RTL_W8(PMCH, RTL_R8(PMCH) | 0x80);
                break;
@@ -4087,6 +4366,8 @@ static void r8168_pll_power_down(struct rtl8169_private *tp)
        case RTL_GIGA_MAC_VER_31:
        case RTL_GIGA_MAC_VER_32:
        case RTL_GIGA_MAC_VER_33:
+       case RTL_GIGA_MAC_VER_45:
+       case RTL_GIGA_MAC_VER_46:
                RTL_W8(PMCH, RTL_R8(PMCH) & ~0x80);
                break;
        case RTL_GIGA_MAC_VER_40:
@@ -4111,6 +4392,10 @@ static void r8168_pll_power_up(struct rtl8169_private *tp)
        case RTL_GIGA_MAC_VER_33:
                RTL_W8(PMCH, RTL_R8(PMCH) | 0x80);
                break;
+       case RTL_GIGA_MAC_VER_45:
+       case RTL_GIGA_MAC_VER_46:
+               RTL_W8(PMCH, RTL_R8(PMCH) | 0xC0);
+               break;
        case RTL_GIGA_MAC_VER_40:
        case RTL_GIGA_MAC_VER_41:
                rtl_w1w0_eri(tp, 0x1a8, ERIAR_MASK_1111, 0xfc000000,
@@ -4153,6 +4438,8 @@ static void rtl_init_pll_power_ops(struct rtl8169_private *tp)
        case RTL_GIGA_MAC_VER_37:
        case RTL_GIGA_MAC_VER_39:
        case RTL_GIGA_MAC_VER_43:
+       case RTL_GIGA_MAC_VER_47:
+       case RTL_GIGA_MAC_VER_48:
                ops->down       = r810x_pll_power_down;
                ops->up         = r810x_pll_power_up;
                break;
@@ -4182,6 +4469,8 @@ static void rtl_init_pll_power_ops(struct rtl8169_private *tp)
        case RTL_GIGA_MAC_VER_41:
        case RTL_GIGA_MAC_VER_42:
        case RTL_GIGA_MAC_VER_44:
+       case RTL_GIGA_MAC_VER_45:
+       case RTL_GIGA_MAC_VER_46:
                ops->down       = r8168_pll_power_down;
                ops->up         = r8168_pll_power_up;
                break;
@@ -4232,6 +4521,10 @@ static void rtl_init_rxcfg(struct rtl8169_private *tp)
        case RTL_GIGA_MAC_VER_42:
        case RTL_GIGA_MAC_VER_43:
        case RTL_GIGA_MAC_VER_44:
+       case RTL_GIGA_MAC_VER_45:
+       case RTL_GIGA_MAC_VER_46:
+       case RTL_GIGA_MAC_VER_47:
+       case RTL_GIGA_MAC_VER_48:
                RTL_W32(RxConfig, RX128_INT_EN | RX_DMA_BURST | RX_EARLY_OFF);
                break;
        default:
@@ -4393,6 +4686,10 @@ static void rtl_init_jumbo_ops(struct rtl8169_private *tp)
        case RTL_GIGA_MAC_VER_42:
        case RTL_GIGA_MAC_VER_43:
        case RTL_GIGA_MAC_VER_44:
+       case RTL_GIGA_MAC_VER_45:
+       case RTL_GIGA_MAC_VER_46:
+       case RTL_GIGA_MAC_VER_47:
+       case RTL_GIGA_MAC_VER_48:
        default:
                ops->disable    = NULL;
                ops->enable     = NULL;
@@ -4495,15 +4792,19 @@ static void rtl8169_hw_reset(struct rtl8169_private *tp)
            tp->mac_version == RTL_GIGA_MAC_VER_31) {
                rtl_udelay_loop_wait_low(tp, &rtl_npq_cond, 20, 42*42);
        } else if (tp->mac_version == RTL_GIGA_MAC_VER_34 ||
-                  tp->mac_version == RTL_GIGA_MAC_VER_35 ||
-                  tp->mac_version == RTL_GIGA_MAC_VER_36 ||
-                  tp->mac_version == RTL_GIGA_MAC_VER_37 ||
-                  tp->mac_version == RTL_GIGA_MAC_VER_40 ||
-                  tp->mac_version == RTL_GIGA_MAC_VER_41 ||
-                  tp->mac_version == RTL_GIGA_MAC_VER_42 ||
-                  tp->mac_version == RTL_GIGA_MAC_VER_43 ||
-                  tp->mac_version == RTL_GIGA_MAC_VER_44 ||
-                  tp->mac_version == RTL_GIGA_MAC_VER_38) {
+                  tp->mac_version == RTL_GIGA_MAC_VER_35 ||
+                  tp->mac_version == RTL_GIGA_MAC_VER_36 ||
+                  tp->mac_version == RTL_GIGA_MAC_VER_37 ||
+                  tp->mac_version == RTL_GIGA_MAC_VER_38 ||
+                  tp->mac_version == RTL_GIGA_MAC_VER_40 ||
+                  tp->mac_version == RTL_GIGA_MAC_VER_41 ||
+                  tp->mac_version == RTL_GIGA_MAC_VER_42 ||
+                  tp->mac_version == RTL_GIGA_MAC_VER_43 ||
+                  tp->mac_version == RTL_GIGA_MAC_VER_44 ||
+                  tp->mac_version == RTL_GIGA_MAC_VER_45 ||
+                  tp->mac_version == RTL_GIGA_MAC_VER_46 ||
+                  tp->mac_version == RTL_GIGA_MAC_VER_47 ||
+                  tp->mac_version == RTL_GIGA_MAC_VER_48) {
                RTL_W8(ChipCmd, RTL_R8(ChipCmd) | StopReq);
                rtl_udelay_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 666);
        } else {
@@ -5330,6 +5631,105 @@ static void rtl_hw_start_8411_2(struct rtl8169_private *tp)
        rtl_ephy_init(tp, e_info_8411_2, ARRAY_SIZE(e_info_8411_2));
 }
 
+static void rtl_hw_start_8168h_1(struct rtl8169_private *tp)
+{
+       void __iomem *ioaddr = tp->mmio_addr;
+       struct pci_dev *pdev = tp->pci_dev;
+       u16 rg_saw_cnt;
+       u32 data;
+       static const struct ephy_info e_info_8168h_1[] = {
+               { 0x1e, 0x0800, 0x0001 },
+               { 0x1d, 0x0000, 0x0800 },
+               { 0x05, 0xffff, 0x2089 },
+               { 0x06, 0xffff, 0x5881 },
+               { 0x04, 0xffff, 0x154a },
+               { 0x01, 0xffff, 0x068b }
+       };
+
+       /* disable aspm and clock request before access ephy */
+       RTL_W8(Config2, RTL_R8(Config2) & ~ClkReqEn);
+       RTL_W8(Config5, RTL_R8(Config5) & ~ASPM_en);
+       rtl_ephy_init(tp, e_info_8168h_1, ARRAY_SIZE(e_info_8168h_1));
+
+       RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO);
+
+       rtl_eri_write(tp, 0xc8, ERIAR_MASK_0101, 0x00080002, ERIAR_EXGMAC);
+       rtl_eri_write(tp, 0xcc, ERIAR_MASK_0001, 0x38, ERIAR_EXGMAC);
+       rtl_eri_write(tp, 0xd0, ERIAR_MASK_0001, 0x48, ERIAR_EXGMAC);
+       rtl_eri_write(tp, 0xe8, ERIAR_MASK_1111, 0x00100006, ERIAR_EXGMAC);
+
+       rtl_csi_access_enable_1(tp);
+
+       rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+       rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x00, 0x01, ERIAR_EXGMAC);
+       rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC);
+
+       rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_1111, 0x0010, 0x00, ERIAR_EXGMAC);
+
+       rtl_w1w0_eri(tp, 0xd4, ERIAR_MASK_1111, 0x1f00, 0x00, ERIAR_EXGMAC);
+
+       rtl_eri_write(tp, 0x5f0, ERIAR_MASK_0011, 0x4f87, ERIAR_EXGMAC);
+
+       RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+       RTL_W32(MISC, RTL_R32(MISC) & ~RXDV_GATED_EN);
+       RTL_W8(MaxTxPacketSize, EarlySize);
+
+       rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
+       rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
+
+       /* Adjust EEE LED frequency */
+       RTL_W8(EEE_LED, RTL_R8(EEE_LED) & ~0x07);
+
+       RTL_W8(DLLPR, RTL_R8(DLLPR) & ~PFM_EN);
+       RTL_W8(DLLPR, RTL_R8(MISC_1) & ~PFM_D3COLD_EN);
+
+       RTL_W8(DLLPR, RTL_R8(DLLPR) & ~TX_10M_PS_EN);
+
+       rtl_w1w0_eri(tp, 0x1b0, ERIAR_MASK_0011, 0x0000, 0x1000, ERIAR_EXGMAC);
+
+       rtl_pcie_state_l2l3_enable(tp, false);
+
+       rtl_writephy(tp, 0x1f, 0x0c42);
+       rg_saw_cnt = rtl_readphy(tp, 0x13);
+       rtl_writephy(tp, 0x1f, 0x0000);
+       if (rg_saw_cnt > 0) {
+               u16 sw_cnt_1ms_ini;
+
+               sw_cnt_1ms_ini = 16000000/rg_saw_cnt;
+               sw_cnt_1ms_ini &= 0x0fff;
+               data = r8168_mac_ocp_read(tp, 0xd412);
+               data &= 0x0fff;
+               data |= sw_cnt_1ms_ini;
+               r8168_mac_ocp_write(tp, 0xd412, data);
+       }
+
+       data = r8168_mac_ocp_read(tp, 0xe056);
+       data &= 0xf0;
+       data |= 0x07;
+       r8168_mac_ocp_write(tp, 0xe056, data);
+
+       data = r8168_mac_ocp_read(tp, 0xe052);
+       data &= 0x8008;
+       data |= 0x6000;
+       r8168_mac_ocp_write(tp, 0xe052, data);
+
+       data = r8168_mac_ocp_read(tp, 0xe0d6);
+       data &= 0x01ff;
+       data |= 0x017f;
+       r8168_mac_ocp_write(tp, 0xe0d6, data);
+
+       data = r8168_mac_ocp_read(tp, 0xd420);
+       data &= 0x0fff;
+       data |= 0x047f;
+       r8168_mac_ocp_write(tp, 0xd420, data);
+
+       r8168_mac_ocp_write(tp, 0xe63e, 0x0001);
+       r8168_mac_ocp_write(tp, 0xe63e, 0x0000);
+       r8168_mac_ocp_write(tp, 0xc094, 0x0000);
+       r8168_mac_ocp_write(tp, 0xc09e, 0x0000);
+}
+
 static void rtl_hw_start_8168(struct net_device *dev)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
@@ -5440,6 +5840,11 @@ static void rtl_hw_start_8168(struct net_device *dev)
                rtl_hw_start_8411_2(tp);
                break;
 
+       case RTL_GIGA_MAC_VER_45:
+       case RTL_GIGA_MAC_VER_46:
+               rtl_hw_start_8168h_1(tp);
+               break;
+
        default:
                printk(KERN_ERR PFX "%s: unknown chipset (mac_version = %d).\n",
                        dev->name, tp->mac_version);
@@ -5655,6 +6060,10 @@ static void rtl_hw_start_8101(struct net_device *dev)
        case RTL_GIGA_MAC_VER_43:
                rtl_hw_start_8168g_2(tp);
                break;
+       case RTL_GIGA_MAC_VER_47:
+       case RTL_GIGA_MAC_VER_48:
+               rtl_hw_start_8168h_1(tp);
+               break;
        }
 
        RTL_W8(Cfg9346, Cfg9346_Lock);
@@ -5895,7 +6304,7 @@ static int rtl8169_xmit_frags(struct rtl8169_private *tp, struct sk_buff *skb,
 {
        struct skb_shared_info *info = skb_shinfo(skb);
        unsigned int cur_frag, entry;
-       struct TxDesc * uninitialized_var(txd);
+       struct TxDesc *uninitialized_var(txd);
        struct device *d = &tp->pci_dev->dev;
 
        entry = tp->cur_tx;
@@ -7110,6 +7519,10 @@ static void rtl_hw_initialize(struct rtl8169_private *tp)
        case RTL_GIGA_MAC_VER_42:
        case RTL_GIGA_MAC_VER_43:
        case RTL_GIGA_MAC_VER_44:
+       case RTL_GIGA_MAC_VER_45:
+       case RTL_GIGA_MAC_VER_46:
+       case RTL_GIGA_MAC_VER_47:
+       case RTL_GIGA_MAC_VER_48:
                rtl_hw_init_8168g(tp);
                break;
 
@@ -7255,8 +7668,19 @@ rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        RTL_W8(Cfg9346, Cfg9346_Unlock);
        RTL_W8(Config1, RTL_R8(Config1) | PMEnable);
        RTL_W8(Config5, RTL_R8(Config5) & (BWF | MWF | UWF | LanWake | PMEStatus));
-       if ((RTL_R8(Config3) & (LinkUp | MagicPacket)) != 0)
-               tp->features |= RTL_FEATURE_WOL;
+       switch (tp->mac_version) {
+       case RTL_GIGA_MAC_VER_45:
+       case RTL_GIGA_MAC_VER_46:
+               if (rtl_eri_read(tp, 0xdc, ERIAR_EXGMAC) & MagicPacket_v2)
+                       tp->features |= RTL_FEATURE_WOL;
+               if ((RTL_R8(Config3) & LinkUp) != 0)
+                       tp->features |= RTL_FEATURE_WOL;
+               break;
+       default:
+               if ((RTL_R8(Config3) & (LinkUp | MagicPacket)) != 0)
+                       tp->features |= RTL_FEATURE_WOL;
+               break;
+       }
        if ((RTL_R8(Config5) & (UWF | BWF | MWF)) != 0)
                tp->features |= RTL_FEATURE_WOL;
        tp->features |= rtl_try_msi(tp, cfg);
@@ -7283,6 +7707,18 @@ rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        u64_stats_init(&tp->tx_stats.syncp);
 
        /* Get MAC address */
+       if (tp->mac_version == RTL_GIGA_MAC_VER_45 ||
+           tp->mac_version == RTL_GIGA_MAC_VER_46 ||
+           tp->mac_version == RTL_GIGA_MAC_VER_47 ||
+           tp->mac_version == RTL_GIGA_MAC_VER_48) {
+               u16 mac_addr[3];
+
+               *(u32 *)&mac_addr[0] = rtl_eri_read(tp, 0xE0, ERIAR_EXGMAC);
+               *(u16 *)&mac_addr[2] = rtl_eri_read(tp, 0xE4, ERIAR_EXGMAC);
+
+               if (is_valid_ether_addr((u8 *)mac_addr))
+                       rtl_rar_set(tp, (u8 *)mac_addr);
+       }
        for (i = 0; i < ETH_ALEN; i++)
                dev->dev_addr[i] = RTL_R8(MAC0 + i);
 
index 9e757c792d846f300288c9848225e1db9a9584fa..196e98a2d93bbfa905a0b13d8a372da00add0f7b 100644 (file)
@@ -5,6 +5,7 @@
 config SH_ETH
        tristate "Renesas SuperH Ethernet support"
        depends on HAS_DMA
+       depends on ARCH_SHMOBILE || SUPERH || COMPILE_TEST
        select CRC32
        select MII
        select MDIO_BITBANG
index 65c220f8661df1a39267e94e9e17de775efd5055..32060984221195793ee6eced35b68d64f559c614 100644 (file)
@@ -78,7 +78,7 @@ static void efx_dequeue_buffer(struct efx_tx_queue *tx_queue,
        if (buffer->flags & EFX_TX_BUF_SKB) {
                (*pkts_compl)++;
                (*bytes_compl) += buffer->skb->len;
-               dev_kfree_skb_any((struct sk_buff *) buffer->skb);
+               dev_consume_skb_any((struct sk_buff *)buffer->skb);
                netif_vdbg(tx_queue->efx, tx_done, tx_queue->efx->net_dev,
                           "TX queue %d transmission id %x complete\n",
                           tx_queue->queue, tx_queue->read_count);
index c553f6b5a9131f0af16230f59ccd0557fe1116a5..cf28daba4346f0c288d1718513554b38e4de2176 100644 (file)
@@ -28,7 +28,7 @@
 
 #include "stmmac.h"
 
-static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
+static int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
 {
        struct stmmac_priv *priv = (struct stmmac_priv *)p;
        unsigned int txsize = priv->dma_tx_size;
@@ -47,7 +47,9 @@ static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
 
        desc->des2 = dma_map_single(priv->device, skb->data,
                                    bmax, DMA_TO_DEVICE);
-       priv->tx_skbuff_dma[entry] = desc->des2;
+       if (dma_mapping_error(priv->device, desc->des2))
+               return -1;
+       priv->tx_skbuff_dma[entry].buf = desc->des2;
        priv->hw->desc->prepare_tx_desc(desc, 1, bmax, csum, STMMAC_CHAIN_MODE);
 
        while (len != 0) {
@@ -59,7 +61,9 @@ static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
                        desc->des2 = dma_map_single(priv->device,
                                                    (skb->data + bmax * i),
                                                    bmax, DMA_TO_DEVICE);
-                       priv->tx_skbuff_dma[entry] = desc->des2;
+                       if (dma_mapping_error(priv->device, desc->des2))
+                               return -1;
+                       priv->tx_skbuff_dma[entry].buf = desc->des2;
                        priv->hw->desc->prepare_tx_desc(desc, 0, bmax, csum,
                                                        STMMAC_CHAIN_MODE);
                        priv->hw->desc->set_tx_owner(desc);
@@ -69,7 +73,9 @@ static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
                        desc->des2 = dma_map_single(priv->device,
                                                    (skb->data + bmax * i), len,
                                                    DMA_TO_DEVICE);
-                       priv->tx_skbuff_dma[entry] = desc->des2;
+                       if (dma_mapping_error(priv->device, desc->des2))
+                               return -1;
+                       priv->tx_skbuff_dma[entry].buf = desc->des2;
                        priv->hw->desc->prepare_tx_desc(desc, 0, len, csum,
                                                        STMMAC_CHAIN_MODE);
                        priv->hw->desc->set_tx_owner(desc);
index de507c32036c75331e393ad5b013890ffffb9d1b..593e6c4144a7c197140f875f73e86c5583c215d1 100644 (file)
@@ -220,10 +220,10 @@ enum dma_irq_status {
        handle_tx = 0x8,
 };
 
-#define        CORE_IRQ_TX_PATH_IN_LPI_MODE    (1 << 1)
-#define        CORE_IRQ_TX_PATH_EXIT_LPI_MODE  (1 << 2)
-#define        CORE_IRQ_RX_PATH_IN_LPI_MODE    (1 << 3)
-#define        CORE_IRQ_RX_PATH_EXIT_LPI_MODE  (1 << 4)
+#define        CORE_IRQ_TX_PATH_IN_LPI_MODE    (1 << 0)
+#define        CORE_IRQ_TX_PATH_EXIT_LPI_MODE  (1 << 1)
+#define        CORE_IRQ_RX_PATH_IN_LPI_MODE    (1 << 2)
+#define        CORE_IRQ_RX_PATH_EXIT_LPI_MODE  (1 << 3)
 
 #define        CORE_PCS_ANE_COMPLETE           (1 << 5)
 #define        CORE_PCS_LINK_STATUS            (1 << 6)
@@ -287,7 +287,7 @@ struct dma_features {
 
 /* Default LPI timers */
 #define STMMAC_DEFAULT_LIT_LS  0x3E8
-#define STMMAC_DEFAULT_TWT_LS  0x0
+#define STMMAC_DEFAULT_TWT_LS  0x1E
 
 #define STMMAC_CHAIN_MODE      0x1
 #define STMMAC_RING_MODE       0x2
@@ -425,7 +425,7 @@ 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 (*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);
@@ -445,6 +445,7 @@ struct mac_device_info {
        int multicast_filter_bins;
        int unicast_filter_entries;
        int mcast_bits_log2;
+       unsigned int rx_csum;
 };
 
 struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr, int mcbins,
index ec632e666c56ad5138384cae4f23e43b45ad4d34..ddc6115720a332794a6488f41a86ff4ae6b6fa32 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <linux/mfd/syscon.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
 #include <linux/of_net.h>
 #include <linux/phy.h>
 #include <linux/regmap.h>
 #define SYSMGR_EMACGRP_CTRL_PHYSEL_WIDTH 2
 #define SYSMGR_EMACGRP_CTRL_PHYSEL_MASK 0x00000003
 
+#define EMAC_SPLITTER_CTRL_REG                 0x0
+#define EMAC_SPLITTER_CTRL_SPEED_MASK          0x3
+#define EMAC_SPLITTER_CTRL_SPEED_10            0x2
+#define EMAC_SPLITTER_CTRL_SPEED_100           0x3
+#define EMAC_SPLITTER_CTRL_SPEED_1000          0x0
+
 struct socfpga_dwmac {
        int     interface;
        u32     reg_offset;
@@ -37,14 +44,46 @@ struct socfpga_dwmac {
        struct  device *dev;
        struct regmap *sys_mgr_base_addr;
        struct reset_control *stmmac_rst;
+       void __iomem *splitter_base;
 };
 
+static void socfpga_dwmac_fix_mac_speed(void *priv, unsigned int speed)
+{
+       struct socfpga_dwmac *dwmac = (struct socfpga_dwmac *)priv;
+       void __iomem *splitter_base = dwmac->splitter_base;
+       u32 val;
+
+       if (!splitter_base)
+               return;
+
+       val = readl(splitter_base + EMAC_SPLITTER_CTRL_REG);
+       val &= ~EMAC_SPLITTER_CTRL_SPEED_MASK;
+
+       switch (speed) {
+       case 1000:
+               val |= EMAC_SPLITTER_CTRL_SPEED_1000;
+               break;
+       case 100:
+               val |= EMAC_SPLITTER_CTRL_SPEED_100;
+               break;
+       case 10:
+               val |= EMAC_SPLITTER_CTRL_SPEED_10;
+               break;
+       default:
+               return;
+       }
+
+       writel(val, splitter_base + EMAC_SPLITTER_CTRL_REG);
+}
+
 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;
+       struct device_node *np_splitter;
+       struct resource res_splitter;
 
        dwmac->stmmac_rst = devm_reset_control_get(dev,
                                                  STMMAC_RESOURCE_NAME);
@@ -73,6 +112,20 @@ static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *
                return -EINVAL;
        }
 
+       np_splitter = of_parse_phandle(np, "altr,emac-splitter", 0);
+       if (np_splitter) {
+               if (of_address_to_resource(np_splitter, 0, &res_splitter)) {
+                       dev_info(dev, "Missing emac splitter address\n");
+                       return -EINVAL;
+               }
+
+               dwmac->splitter_base = devm_ioremap_resource(dev, &res_splitter);
+               if (!dwmac->splitter_base) {
+                       dev_info(dev, "Failed to mapping emac splitter\n");
+                       return -EINVAL;
+               }
+       }
+
        dwmac->reg_offset = reg_offset;
        dwmac->reg_shift = reg_shift;
        dwmac->sys_mgr_base_addr = sys_mgr_base_addr;
@@ -91,6 +144,7 @@ static int socfpga_dwmac_setup(struct socfpga_dwmac *dwmac)
 
        switch (phymode) {
        case PHY_INTERFACE_MODE_RGMII:
+       case PHY_INTERFACE_MODE_RGMII_ID:
                val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII;
                break;
        case PHY_INTERFACE_MODE_MII:
@@ -102,6 +156,13 @@ static int socfpga_dwmac_setup(struct socfpga_dwmac *dwmac)
                return -EINVAL;
        }
 
+       /* Overwrite val to GMII if splitter core is enabled. The phymode here
+        * is the actual phy mode on phy hardware, but phy interface from
+        * EMAC core is GMII.
+        */
+       if (dwmac->splitter_base)
+               val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII;
+
        regmap_read(sys_mgr_base_addr, reg_offset, &ctrl);
        ctrl &= ~(SYSMGR_EMACGRP_CTRL_PHYSEL_MASK << reg_shift);
        ctrl |= val << reg_shift;
@@ -196,4 +257,5 @@ const struct stmmac_of_data socfpga_gmac_data = {
        .setup = socfpga_dwmac_probe,
        .init = socfpga_dwmac_init,
        .exit = socfpga_dwmac_exit,
+       .fix_mac_speed = socfpga_dwmac_fix_mac_speed,
 };
index 71b5419256c138e335c77aab87cf37784ff79037..64d8f56a9c1732f9199cc3a748e25ae8c1107ed7 100644 (file)
@@ -153,7 +153,7 @@ enum inter_frame_gap {
 #define GMAC_CONTROL_RE                0x00000004      /* Receiver Enable */
 
 #define GMAC_CORE_INIT (GMAC_CONTROL_JD | GMAC_CONTROL_PS | GMAC_CONTROL_ACS | \
-                       GMAC_CONTROL_BE)
+                       GMAC_CONTROL_BE | GMAC_CONTROL_DCRS)
 
 /* GMAC Frame Filter defines */
 #define GMAC_FRAME_FILTER_PR   0x00000001      /* Promiscuous Mode */
index d8ef18786a1cadae60f5d550269a0036a3f24661..5efe60ea6526b3d06305530b75240b9de719f1f3 100644 (file)
@@ -58,7 +58,11 @@ static int dwmac1000_rx_ipc_enable(struct mac_device_info *hw)
        void __iomem *ioaddr = hw->pcsr;
        u32 value = readl(ioaddr + GMAC_CONTROL);
 
-       value |= GMAC_CONTROL_IPC;
+       if (hw->rx_csum)
+               value |= GMAC_CONTROL_IPC;
+       else
+               value &= ~GMAC_CONTROL_IPC;
+
        writel(value, ioaddr + GMAC_CONTROL);
 
        value = readl(ioaddr + GMAC_CONTROL);
index 8607488cbcfcfaea7bc70510f0a3f601c5dade7d..192c2491330b1070348f5ccf5c5eb51d492e7b24 100644 (file)
@@ -68,7 +68,7 @@ struct stmmac_counters {
        unsigned int mmc_rx_octetcount_g;
        unsigned int mmc_rx_broadcastframe_g;
        unsigned int mmc_rx_multicastframe_g;
-       unsigned int mmc_rx_crc_errror;
+       unsigned int mmc_rx_crc_error;
        unsigned int mmc_rx_align_error;
        unsigned int mmc_rx_run_error;
        unsigned int mmc_rx_jabber_error;
index 50617c5a0bdb5e63fc930f7af277a1a9fb139af4..08c483bd2ec7bd94d5434f9567c75f609ce27d35 100644 (file)
@@ -196,7 +196,7 @@ void dwmac_mmc_read(void __iomem *ioaddr, struct stmmac_counters *mmc)
        mmc->mmc_rx_octetcount_g += readl(ioaddr + MMC_RX_OCTETCOUNT_G);
        mmc->mmc_rx_broadcastframe_g += readl(ioaddr + MMC_RX_BROADCASTFRAME_G);
        mmc->mmc_rx_multicastframe_g += readl(ioaddr + MMC_RX_MULTICASTFRAME_G);
-       mmc->mmc_rx_crc_errror += readl(ioaddr + MMC_RX_CRC_ERRROR);
+       mmc->mmc_rx_crc_error += readl(ioaddr + MMC_RX_CRC_ERRROR);
        mmc->mmc_rx_align_error += readl(ioaddr + MMC_RX_ALIGN_ERROR);
        mmc->mmc_rx_run_error += readl(ioaddr + MMC_RX_RUN_ERROR);
        mmc->mmc_rx_jabber_error += readl(ioaddr + MMC_RX_JABBER_ERROR);
index 650a4be6bce5243e046fcd226719e669f66444e8..5dd50c6cda5be0280e235152057a329a89fb187c 100644 (file)
@@ -28,7 +28,7 @@
 
 #include "stmmac.h"
 
-static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
+static int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
 {
        struct stmmac_priv *priv = (struct stmmac_priv *)p;
        unsigned int txsize = priv->dma_tx_size;
@@ -53,7 +53,10 @@ static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
 
                desc->des2 = dma_map_single(priv->device, skb->data,
                                            bmax, DMA_TO_DEVICE);
-               priv->tx_skbuff_dma[entry] = desc->des2;
+               if (dma_mapping_error(priv->device, desc->des2))
+                       return -1;
+
+               priv->tx_skbuff_dma[entry].buf = desc->des2;
                desc->des3 = desc->des2 + BUF_SIZE_4KiB;
                priv->hw->desc->prepare_tx_desc(desc, 1, bmax, csum,
                                                STMMAC_RING_MODE);
@@ -68,7 +71,9 @@ static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
 
                desc->des2 = dma_map_single(priv->device, skb->data + bmax,
                                            len, DMA_TO_DEVICE);
-               priv->tx_skbuff_dma[entry] = desc->des2;
+               if (dma_mapping_error(priv->device, desc->des2))
+                       return -1;
+               priv->tx_skbuff_dma[entry].buf = desc->des2;
                desc->des3 = desc->des2 + BUF_SIZE_4KiB;
                priv->hw->desc->prepare_tx_desc(desc, 0, len, csum,
                                                STMMAC_RING_MODE);
@@ -77,7 +82,9 @@ static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
        } else {
                desc->des2 = dma_map_single(priv->device, skb->data,
                                            nopaged_len, DMA_TO_DEVICE);
-               priv->tx_skbuff_dma[entry] = desc->des2;
+               if (dma_mapping_error(priv->device, desc->des2))
+                       return -1;
+               priv->tx_skbuff_dma[entry].buf = desc->des2;
                desc->des3 = desc->des2 + BUF_SIZE_4KiB;
                priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len, csum,
                                                STMMAC_RING_MODE);
index ca01035634a76fbc88414f6550849cfa1c772403..58097c0e2ad502699ace45392bb3f12855101625 100644 (file)
 #include <linux/ptp_clock_kernel.h>
 #include <linux/reset.h>
 
+struct stmmac_tx_info {
+       dma_addr_t buf;
+       bool map_as_page;
+};
+
 struct stmmac_priv {
        /* Frequently used values are kept adjacent for cache effect */
        struct dma_extended_desc *dma_etx ____cacheline_aligned_in_smp;
@@ -45,7 +50,7 @@ struct stmmac_priv {
        u32 tx_count_frames;
        u32 tx_coal_frames;
        u32 tx_coal_timer;
-       dma_addr_t *tx_skbuff_dma;
+       struct stmmac_tx_info *tx_skbuff_dma;
        dma_addr_t dma_tx_phy;
        int tx_coalesce;
        int hwts_tx_en;
@@ -105,6 +110,8 @@ struct stmmac_priv {
        struct ptp_clock *ptp_clock;
        struct ptp_clock_info ptp_clock_ops;
        unsigned int default_addend;
+       struct clk *clk_ptp_ref;
+       unsigned int clk_ptp_rate;
        u32 adv_ts;
        int use_riwt;
        int irq_wake;
index 9af50bae4dde67c543c15e0344f90ac9d53fd2b8..3a08a1f78c732b49992cc711907131d74b5e18e8 100644 (file)
@@ -175,7 +175,7 @@ static const struct stmmac_stats stmmac_mmc[] = {
        STMMAC_MMC_STAT(mmc_rx_octetcount_g),
        STMMAC_MMC_STAT(mmc_rx_broadcastframe_g),
        STMMAC_MMC_STAT(mmc_rx_multicastframe_g),
-       STMMAC_MMC_STAT(mmc_rx_crc_errror),
+       STMMAC_MMC_STAT(mmc_rx_crc_error),
        STMMAC_MMC_STAT(mmc_rx_align_error),
        STMMAC_MMC_STAT(mmc_rx_run_error),
        STMMAC_MMC_STAT(mmc_rx_jabber_error),
@@ -261,11 +261,11 @@ static int stmmac_ethtool_getsettings(struct net_device *dev,
                ethtool_cmd_speed_set(cmd, priv->xstats.pcs_speed);
 
                /* Get and convert ADV/LP_ADV from the HW AN registers */
-               if (priv->hw->mac->get_adv)
-                       priv->hw->mac->get_adv(priv->hw, &adv);
-               else
+               if (!priv->hw->mac->get_adv)
                        return -EOPNOTSUPP;     /* should never happen indeed */
 
+               priv->hw->mac->get_adv(priv->hw, &adv);
+
                /* Encoding of PSE bits is defined in 802.3z, 37.2.1.4 */
 
                if (adv.pause & STMMAC_PCS_PAUSE)
@@ -340,19 +340,17 @@ static int stmmac_ethtool_setsettings(struct net_device *dev,
                if (cmd->autoneg != AUTONEG_ENABLE)
                        return -EINVAL;
 
-               if (cmd->autoneg == AUTONEG_ENABLE) {
-                       mask &= (ADVERTISED_1000baseT_Half |
+               mask &= (ADVERTISED_1000baseT_Half |
                        ADVERTISED_1000baseT_Full |
                        ADVERTISED_100baseT_Half |
                        ADVERTISED_100baseT_Full |
                        ADVERTISED_10baseT_Half |
                        ADVERTISED_10baseT_Full);
 
-                       spin_lock(&priv->lock);
-                       if (priv->hw->mac->ctrl_ane)
-                               priv->hw->mac->ctrl_ane(priv->hw, 1);
-                       spin_unlock(&priv->lock);
-               }
+               spin_lock(&priv->lock);
+               if (priv->hw->mac->ctrl_ane)
+                       priv->hw->mac->ctrl_ane(priv->hw, 1);
+               spin_unlock(&priv->lock);
 
                return 0;
        }
index 08addd65372818f48075b585eeb1d36ab682025b..9dbb02d9d9c255c9c2515cac80340affe266617a 100644 (file)
@@ -275,6 +275,7 @@ static void stmmac_eee_ctrl_timer(unsigned long arg)
  */
 bool stmmac_eee_init(struct stmmac_priv *priv)
 {
+       char *phy_bus_name = priv->plat->phy_bus_name;
        bool ret = false;
 
        /* Using PCS we cannot dial with the phy registers at this stage
@@ -284,6 +285,10 @@ bool stmmac_eee_init(struct stmmac_priv *priv)
            (priv->pcs == STMMAC_PCS_RTBI))
                goto out;
 
+       /* Never init EEE in case of a switch is attached */
+       if (phy_bus_name && (!strcmp(phy_bus_name, "fixed")))
+               goto out;
+
        /* MAC core supports the EEE feature. */
        if (priv->dma_cap.eee) {
                int tx_lpi_timer = priv->tx_lpi_timer;
@@ -316,10 +321,9 @@ bool stmmac_eee_init(struct stmmac_priv *priv)
                        priv->hw->mac->set_eee_timer(priv->hw,
                                                     STMMAC_DEFAULT_LIT_LS,
                                                     tx_lpi_timer);
-               } else
-                       /* Set HW EEE according to the speed */
-                       priv->hw->mac->set_eee_pls(priv->hw,
-                                                  priv->phydev->link);
+               }
+               /* Set HW EEE according to the speed */
+               priv->hw->mac->set_eee_pls(priv->hw, priv->phydev->link);
 
                pr_debug("stmmac: Energy-Efficient Ethernet initialized\n");
 
@@ -603,16 +607,16 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
                /* calculate default added value:
                 * formula is :
                 * addend = (2^32)/freq_div_ratio;
-                * where, freq_div_ratio = STMMAC_SYSCLOCK/50MHz
-                * hence, addend = ((2^32) * 50MHz)/STMMAC_SYSCLOCK;
-                * NOTE: STMMAC_SYSCLOCK should be >= 50MHz to
+                * where, freq_div_ratio = clk_ptp_ref_i/50MHz
+                * hence, addend = ((2^32) * 50MHz)/clk_ptp_ref_i;
+                * NOTE: clk_ptp_ref_i should be >= 50MHz to
                 *       achive 20ns accuracy.
                 *
                 * 2^x * y == (y << x), hence
                 * 2^32 * 50000000 ==> (50000000 << 32)
                 */
                temp = (u64) (50000000ULL << 32);
-               priv->default_addend = div_u64(temp, STMMAC_SYSCLOCK);
+               priv->default_addend = div_u64(temp, priv->clk_ptp_rate);
                priv->hw->ptp->config_addend(priv->ioaddr,
                                             priv->default_addend);
 
@@ -638,6 +642,16 @@ static int stmmac_init_ptp(struct stmmac_priv *priv)
        if (!(priv->dma_cap.time_stamp || priv->dma_cap.atime_stamp))
                return -EOPNOTSUPP;
 
+       /* Fall-back to main clock in case of no PTP ref is passed */
+       priv->clk_ptp_ref = devm_clk_get(priv->device, "clk_ptp_ref");
+       if (IS_ERR(priv->clk_ptp_ref)) {
+               priv->clk_ptp_rate = clk_get_rate(priv->stmmac_clk);
+               priv->clk_ptp_ref = NULL;
+       } else {
+               clk_prepare_enable(priv->clk_ptp_ref);
+               priv->clk_ptp_rate = clk_get_rate(priv->clk_ptp_ref);
+       }
+
        priv->adv_ts = 0;
        if (priv->dma_cap.atime_stamp && priv->extend_desc)
                priv->adv_ts = 1;
@@ -657,6 +671,8 @@ static int stmmac_init_ptp(struct stmmac_priv *priv)
 
 static void stmmac_release_ptp(struct stmmac_priv *priv)
 {
+       if (priv->clk_ptp_ref)
+               clk_disable_unprepare(priv->clk_ptp_ref);
        stmmac_ptp_unregister(priv);
 }
 
@@ -818,7 +834,7 @@ static int stmmac_init_phy(struct net_device *dev)
        /* Stop Advertising 1000BASE Capability if interface is not GMII */
        if ((interface == PHY_INTERFACE_MODE_MII) ||
            (interface == PHY_INTERFACE_MODE_RMII) ||
-               (max_speed < 1000 &&  max_speed > 0))
+               (max_speed < 1000 && max_speed > 0))
                phydev->advertising &= ~(SUPPORTED_1000baseT_Half |
                                         SUPPORTED_1000baseT_Full);
 
@@ -1061,7 +1077,8 @@ static int init_dma_desc_rings(struct net_device *dev)
                else
                        p = priv->dma_tx + i;
                p->des2 = 0;
-               priv->tx_skbuff_dma[i] = 0;
+               priv->tx_skbuff_dma[i].buf = 0;
+               priv->tx_skbuff_dma[i].map_as_page = false;
                priv->tx_skbuff[i] = NULL;
        }
 
@@ -1100,17 +1117,24 @@ static void dma_free_tx_skbufs(struct stmmac_priv *priv)
                else
                        p = priv->dma_tx + i;
 
-               if (priv->tx_skbuff_dma[i]) {
-                       dma_unmap_single(priv->device,
-                                        priv->tx_skbuff_dma[i],
-                                        priv->hw->desc->get_tx_len(p),
-                                        DMA_TO_DEVICE);
-                       priv->tx_skbuff_dma[i] = 0;
+               if (priv->tx_skbuff_dma[i].buf) {
+                       if (priv->tx_skbuff_dma[i].map_as_page)
+                               dma_unmap_page(priv->device,
+                                              priv->tx_skbuff_dma[i].buf,
+                                              priv->hw->desc->get_tx_len(p),
+                                              DMA_TO_DEVICE);
+                       else
+                               dma_unmap_single(priv->device,
+                                                priv->tx_skbuff_dma[i].buf,
+                                                priv->hw->desc->get_tx_len(p),
+                                                DMA_TO_DEVICE);
                }
 
                if (priv->tx_skbuff[i] != NULL) {
                        dev_kfree_skb_any(priv->tx_skbuff[i]);
                        priv->tx_skbuff[i] = NULL;
+                       priv->tx_skbuff_dma[i].buf = 0;
+                       priv->tx_skbuff_dma[i].map_as_page = false;
                }
        }
 }
@@ -1131,7 +1155,8 @@ static int alloc_dma_desc_resources(struct stmmac_priv *priv)
        if (!priv->rx_skbuff)
                goto err_rx_skbuff;
 
-       priv->tx_skbuff_dma = kmalloc_array(txsize, sizeof(dma_addr_t),
+       priv->tx_skbuff_dma = kmalloc_array(txsize,
+                                           sizeof(*priv->tx_skbuff_dma),
                                            GFP_KERNEL);
        if (!priv->tx_skbuff_dma)
                goto err_tx_skbuff_dma;
@@ -1293,12 +1318,19 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
                        pr_debug("%s: curr %d, dirty %d\n", __func__,
                                 priv->cur_tx, priv->dirty_tx);
 
-               if (likely(priv->tx_skbuff_dma[entry])) {
-                       dma_unmap_single(priv->device,
-                                        priv->tx_skbuff_dma[entry],
-                                        priv->hw->desc->get_tx_len(p),
-                                        DMA_TO_DEVICE);
-                       priv->tx_skbuff_dma[entry] = 0;
+               if (likely(priv->tx_skbuff_dma[entry].buf)) {
+                       if (priv->tx_skbuff_dma[entry].map_as_page)
+                               dma_unmap_page(priv->device,
+                                              priv->tx_skbuff_dma[entry].buf,
+                                              priv->hw->desc->get_tx_len(p),
+                                              DMA_TO_DEVICE);
+                       else
+                               dma_unmap_single(priv->device,
+                                                priv->tx_skbuff_dma[entry].buf,
+                                                priv->hw->desc->get_tx_len(p),
+                                                DMA_TO_DEVICE);
+                       priv->tx_skbuff_dma[entry].buf = 0;
+                       priv->tx_skbuff_dma[entry].map_as_page = false;
                }
                priv->hw->mode->clean_desc3(priv, p);
 
@@ -1637,6 +1669,13 @@ static int stmmac_hw_setup(struct net_device *dev)
        /* Initialize the MAC Core */
        priv->hw->mac->core_init(priv->hw, dev->mtu);
 
+       ret = priv->hw->mac->rx_ipc(priv->hw);
+       if (!ret) {
+               pr_warn(" RX IPC Checksum Offload disabled\n");
+               priv->plat->rx_coe = STMMAC_RX_COE_NONE;
+               priv->hw->rx_csum = 0;
+       }
+
        /* Enable the MAC Rx/Tx */
        stmmac_set_mac(priv->ioaddr, true);
 
@@ -1887,12 +1926,16 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
        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;
+               if (dma_mapping_error(priv->device, desc->des2))
+                       goto dma_map_err;
+               priv->tx_skbuff_dma[entry].buf = desc->des2;
                priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len,
                                                csum_insertion, priv->mode);
        } else {
                desc = first;
                entry = priv->hw->mode->jumbo_frm(priv, skb, csum_insertion);
+               if (unlikely(entry < 0))
+                       goto dma_map_err;
        }
 
        for (i = 0; i < nfrags; i++) {
@@ -1908,7 +1951,11 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
 
                desc->des2 = skb_frag_dma_map(priv->device, frag, 0, len,
                                              DMA_TO_DEVICE);
-               priv->tx_skbuff_dma[entry] = desc->des2;
+               if (dma_mapping_error(priv->device, desc->des2))
+                       goto dma_map_err; /* should reuse desc w/o issues */
+
+               priv->tx_skbuff_dma[entry].buf = desc->des2;
+               priv->tx_skbuff_dma[entry].map_as_page = true;
                priv->hw->desc->prepare_tx_desc(desc, 0, len, csum_insertion,
                                                priv->mode);
                wmb();
@@ -1975,7 +2022,12 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
        priv->hw->dma->enable_dma_transmission(priv->ioaddr);
 
        spin_unlock(&priv->tx_lock);
+       return NETDEV_TX_OK;
 
+dma_map_err:
+       dev_err(priv->device, "Tx dma map failed\n");
+       dev_kfree_skb(skb);
+       priv->dev->stats.tx_dropped++;
        return NETDEV_TX_OK;
 }
 
@@ -2028,7 +2080,12 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv)
                        priv->rx_skbuff_dma[entry] =
                            dma_map_single(priv->device, skb->data, bfsize,
                                           DMA_FROM_DEVICE);
-
+                       if (dma_mapping_error(priv->device,
+                                             priv->rx_skbuff_dma[entry])) {
+                               dev_err(priv->device, "Rx dma map failed\n");
+                               dev_kfree_skb(skb);
+                               break;
+                       }
                        p->des2 = priv->rx_skbuff_dma[entry];
 
                        priv->hw->mode->refill_desc3(priv, p);
@@ -2055,7 +2112,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
        unsigned int entry = priv->cur_rx % rxsize;
        unsigned int next_entry;
        unsigned int count = 0;
-       int coe = priv->plat->rx_coe;
+       int coe = priv->hw->rx_csum;
 
        if (netif_msg_rx_status(priv)) {
                pr_debug("%s: descriptor ring:\n", __func__);
@@ -2276,8 +2333,7 @@ static netdev_features_t stmmac_fix_features(struct net_device *dev,
 
        if (priv->plat->rx_coe == STMMAC_RX_COE_NONE)
                features &= ~NETIF_F_RXCSUM;
-       else if (priv->plat->rx_coe == STMMAC_RX_COE_TYPE1)
-               features &= ~NETIF_F_IPV6_CSUM;
+
        if (!priv->plat->tx_coe)
                features &= ~NETIF_F_ALL_CSUM;
 
@@ -2292,6 +2348,24 @@ static netdev_features_t stmmac_fix_features(struct net_device *dev,
        return features;
 }
 
+static int stmmac_set_features(struct net_device *netdev,
+                              netdev_features_t features)
+{
+       struct stmmac_priv *priv = netdev_priv(netdev);
+
+       /* Keep the COE Type in case of csum is supporting */
+       if (features & NETIF_F_RXCSUM)
+               priv->hw->rx_csum = priv->plat->rx_coe;
+       else
+               priv->hw->rx_csum = 0;
+       /* No check needed because rx_coe has been set before and it will be
+        * fixed in case of issue.
+        */
+       priv->hw->mac->rx_ipc(priv->hw);
+
+       return 0;
+}
+
 /**
  *  stmmac_interrupt - main ISR
  *  @irq: interrupt number.
@@ -2572,6 +2646,7 @@ static const struct net_device_ops stmmac_netdev_ops = {
        .ndo_stop = stmmac_release,
        .ndo_change_mtu = stmmac_change_mtu,
        .ndo_fix_features = stmmac_fix_features,
+       .ndo_set_features = stmmac_set_features,
        .ndo_set_rx_mode = stmmac_set_rx_mode,
        .ndo_tx_timeout = stmmac_tx_timeout,
        .ndo_do_ioctl = stmmac_ioctl,
@@ -2592,7 +2667,6 @@ static const struct net_device_ops stmmac_netdev_ops = {
  */
 static int stmmac_hw_init(struct stmmac_priv *priv)
 {
-       int ret;
        struct mac_device_info *mac;
 
        /* Identify the MAC HW device */
@@ -2649,15 +2723,11 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
        /* To use alternate (extended) or normal descriptor structures */
        stmmac_selec_desc_mode(priv);
 
-       ret = priv->hw->mac->rx_ipc(priv->hw);
-       if (!ret) {
-               pr_warn(" RX IPC Checksum Offload not configured.\n");
-               priv->plat->rx_coe = STMMAC_RX_COE_NONE;
-       }
-
-       if (priv->plat->rx_coe)
+       if (priv->plat->rx_coe) {
+               priv->hw->rx_csum = priv->plat->rx_coe;
                pr_info(" RX Checksum Offload Engine supported (type %d)\n",
                        priv->plat->rx_coe);
+       }
        if (priv->plat->tx_coe)
                pr_info(" TX Checksum insertion supported\n");
 
index a5b1e1b776fe3313c5c9852062ed66ea1547c285..b735fa22ac95a95fa7bef8b4c4672637bb356148 100644 (file)
@@ -253,7 +253,7 @@ int stmmac_mdio_register(struct net_device *ndev)
                        }
 
                        /*
-                        * If we're  going to bind the MAC to this PHY bus,
+                        * 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.
                         */
@@ -282,7 +282,7 @@ int stmmac_mdio_register(struct net_device *ndev)
        }
 
        if (!found) {
-               pr_warning("%s: No PHY found\n", ndev->name);
+               pr_warn("%s: No PHY found\n", ndev->name);
                mdiobus_unregister(new_bus);
                mdiobus_free(new_bus);
                return -ENODEV;
index b7ad3565566cc8a09b7964fcb59aca3921e8e57c..c5ee79d8a8c56478f9987efc2c0631c140aafc0d 100644 (file)
@@ -206,6 +206,7 @@ void stmmac_ptp_unregister(struct stmmac_priv *priv)
 {
        if (priv->ptp_clock) {
                ptp_clock_unregister(priv->ptp_clock);
+               priv->ptp_clock = NULL;
                pr_debug("Removed PTP HW clock successfully on %s\n",
                         priv->dev->name);
        }
index 3dbc047622fa8bee67ed44213b0f8cd74a4ca956..4535df37c22767824d1f7bbe6db56a8e3d0644ab 100644 (file)
@@ -25,8 +25,6 @@
 #ifndef __STMMAC_PTP_H__
 #define __STMMAC_PTP_H__
 
-#define STMMAC_SYSCLOCK 62500000
-
 /* IEEE 1588 PTP register offsets */
 #define PTP_TCR                0x0700  /* Timestamp Control Reg */
 #define PTP_SSIR       0x0704  /* Sub-Second Increment Reg */
index 37f87ff28f036c7f46048826a82d790d371ccc43..02d370e58110de31b74d1d1b89f4038b7b476a3f 100644 (file)
@@ -4962,7 +4962,7 @@ static int cas_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        pci_cmd |= PCI_COMMAND_PARITY;
        pci_write_config_word(pdev, PCI_COMMAND, pci_cmd);
        if (pci_try_set_mwi(pdev))
-               pr_warning("Could not enable MWI for %s\n", pci_name(pdev));
+               pr_warn("Could not enable MWI for %s\n", pci_name(pdev));
 
        cas_program_bridge(pdev);
 
index 8216be46540ff24f41f020116c009a21005235a2..904fd1ab5f6e3762703d2931cf8fb6963c53c32c 100644 (file)
@@ -8717,8 +8717,8 @@ static void niu_divide_channels(struct niu_parent *parent,
                        parent->txchan_per_port[i] = 1;
        }
        if (tot_rx < NIU_NUM_RXCHAN || tot_tx < NIU_NUM_TXCHAN) {
-               pr_warning("niu%d: Driver bug, wasted channels, RX[%d] TX[%d]\n",
-                          parent->index, tot_rx, tot_tx);
+               pr_warn("niu%d: Driver bug, wasted channels, RX[%d] TX[%d]\n",
+                       parent->index, tot_rx, tot_tx);
        }
 }
 
index f7415b6bf141caf5359986ae5de290937e01c7e9..fef5dec2cffe9c3bb7f09bbe728ab2dc54b0cba9 100644 (file)
@@ -115,7 +115,7 @@ static const struct pci_device_id gem_pci_tbl[] = {
 
 MODULE_DEVICE_TABLE(pci, gem_pci_tbl);
 
-static u16 __phy_read(struct gem *gp, int phy_addr, int reg)
+static u16 __sungem_phy_read(struct gem *gp, int phy_addr, int reg)
 {
        u32 cmd;
        int limit = 10000;
@@ -141,18 +141,18 @@ static u16 __phy_read(struct gem *gp, int phy_addr, int reg)
        return cmd & MIF_FRAME_DATA;
 }
 
-static inline int _phy_read(struct net_device *dev, int mii_id, int reg)
+static inline int _sungem_phy_read(struct net_device *dev, int mii_id, int reg)
 {
        struct gem *gp = netdev_priv(dev);
-       return __phy_read(gp, mii_id, reg);
+       return __sungem_phy_read(gp, mii_id, reg);
 }
 
-static inline u16 phy_read(struct gem *gp, int reg)
+static inline u16 sungem_phy_read(struct gem *gp, int reg)
 {
-       return __phy_read(gp, gp->mii_phy_addr, reg);
+       return __sungem_phy_read(gp, gp->mii_phy_addr, reg);
 }
 
-static void __phy_write(struct gem *gp, int phy_addr, int reg, u16 val)
+static void __sungem_phy_write(struct gem *gp, int phy_addr, int reg, u16 val)
 {
        u32 cmd;
        int limit = 10000;
@@ -174,15 +174,15 @@ static void __phy_write(struct gem *gp, int phy_addr, int reg, u16 val)
        }
 }
 
-static inline void _phy_write(struct net_device *dev, int mii_id, int reg, int val)
+static inline void _sungem_phy_write(struct net_device *dev, int mii_id, int reg, int val)
 {
        struct gem *gp = netdev_priv(dev);
-       __phy_write(gp, mii_id, reg, val & 0xffff);
+       __sungem_phy_write(gp, mii_id, reg, val & 0xffff);
 }
 
-static inline void phy_write(struct gem *gp, int reg, u16 val)
+static inline void sungem_phy_write(struct gem *gp, int reg, u16 val)
 {
-       __phy_write(gp, gp->mii_phy_addr, reg, val);
+       __sungem_phy_write(gp, gp->mii_phy_addr, reg, val);
 }
 
 static inline void gem_enable_ints(struct gem *gp)
@@ -1687,9 +1687,9 @@ static void gem_init_phy(struct gem *gp)
                        /* Some PHYs used by apple have problem getting back to us,
                         * we do an additional reset here
                         */
-                       phy_write(gp, MII_BMCR, BMCR_RESET);
+                       sungem_phy_write(gp, MII_BMCR, BMCR_RESET);
                        msleep(20);
-                       if (phy_read(gp, MII_BMCR) != 0xffff)
+                       if (sungem_phy_read(gp, MII_BMCR) != 0xffff)
                                break;
                        if (i == 2)
                                netdev_warn(gp->dev, "GMAC PHY not responding !\n");
@@ -2012,7 +2012,7 @@ static int gem_check_invariants(struct gem *gp)
 
                for (i = 0; i < 32; i++) {
                        gp->mii_phy_addr = i;
-                       if (phy_read(gp, MII_BMCR) != 0xffff)
+                       if (sungem_phy_read(gp, MII_BMCR) != 0xffff)
                                break;
                }
                if (i == 32) {
@@ -2696,13 +2696,13 @@ static int gem_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                /* Fallthrough... */
 
        case SIOCGMIIREG:               /* Read MII PHY register. */
-               data->val_out = __phy_read(gp, data->phy_id & 0x1f,
+               data->val_out = __sungem_phy_read(gp, data->phy_id & 0x1f,
                                           data->reg_num & 0x1f);
                rc = 0;
                break;
 
        case SIOCSMIIREG:               /* Write MII PHY register. */
-               __phy_write(gp, data->phy_id & 0x1f, data->reg_num & 0x1f,
+               __sungem_phy_write(gp, data->phy_id & 0x1f, data->reg_num & 0x1f,
                            data->val_in);
                rc = 0;
                break;
@@ -2933,8 +2933,8 @@ static int gem_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        /* Fill up the mii_phy structure (even if we won't use it) */
        gp->phy_mii.dev = dev;
-       gp->phy_mii.mdio_read = _phy_read;
-       gp->phy_mii.mdio_write = _phy_write;
+       gp->phy_mii.mdio_read = _sungem_phy_read;
+       gp->phy_mii.mdio_write = _sungem_phy_write;
 #ifdef CONFIG_PPC_PMAC
        gp->phy_mii.platform_data = gp->of_node;
 #endif
index 23c89ab5a6ada1ade365939dcd7bb28da44ca736..a4657a401278ea702620ac9d29becf9b806fd68f 100644 (file)
@@ -534,7 +534,7 @@ static void vnet_event(void *arg, int event)
        }
 
        if (unlikely(event != LDC_EVENT_DATA_READY)) {
-               pr_warning("Unexpected LDC event %d\n", event);
+               pr_warn("Unexpected LDC event %d\n", event);
                spin_unlock_irqrestore(&vio->lock, flags);
                return;
        }
index f9bcf7aa88ca3a2d6aa4b607bd134e0c36fc6d91..dd9430043536541b577a4b90418cebb33a67baf3 100644 (file)
@@ -1207,7 +1207,6 @@ static int cpmac_remove(struct platform_device *pdev)
 static struct platform_driver cpmac_driver = {
        .driver = {
                .name   = "cpmac",
-               .owner  = THIS_MODULE,
        },
        .probe  = cpmac_probe,
        .remove = cpmac_remove,
index aa8bf45e53dc9b0ddab4265b2e527067339a00fc..0ea78326cc2165d63b82eff89c5b90a49ecb9ac5 100644 (file)
@@ -211,7 +211,6 @@ static struct platform_driver cpsw_phy_sel_driver = {
        .probe          = cpsw_phy_sel_probe,
        .driver         = {
                .name   = "cpsw-phy-sel",
-               .owner  = THIS_MODULE,
                .of_match_table = cpsw_phy_sel_id_table,
        },
 };
index 999fb72688d226317d0565c936a286386ae6dd98..5c3f1f3ad16f68e397ca7873a013577d320c8b7b 100644 (file)
@@ -397,6 +397,8 @@ struct cpsw_priv {
        struct cpdma_ctlr               *dma;
        struct cpdma_chan               *txch, *rxch;
        struct cpsw_ale                 *ale;
+       bool                            rx_pause;
+       bool                            tx_pause;
        /* snapshot of IRQ numbers */
        u32 irqs_table[4];
        u32 num_irqs;
@@ -832,6 +834,12 @@ static void _cpsw_adjust_link(struct cpsw_slave *slave,
                else if (phy->speed == 10)
                        mac_control |= BIT(18); /* In Band mode */
 
+               if (priv->rx_pause)
+                       mac_control |= BIT(3);
+
+               if (priv->tx_pause)
+                       mac_control |= BIT(4);
+
                *link = true;
        } else {
                mac_control = 0;
@@ -1223,6 +1231,9 @@ static int cpsw_ndo_open(struct net_device *ndev)
                /* enable statistics collection only on all ports */
                __raw_writel(0x7, &priv->regs->stat_port_en);
 
+               /* Enable internal fifo flow control */
+               writel(0x7, &priv->regs->flow_control);
+
                if (WARN_ON(!priv->data.rx_descs))
                        priv->data.rx_descs = 128;
 
@@ -1784,6 +1795,30 @@ static int cpsw_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
                return -EOPNOTSUPP;
 }
 
+static void cpsw_get_pauseparam(struct net_device *ndev,
+                               struct ethtool_pauseparam *pause)
+{
+       struct cpsw_priv *priv = netdev_priv(ndev);
+
+       pause->autoneg = AUTONEG_DISABLE;
+       pause->rx_pause = priv->rx_pause ? true : false;
+       pause->tx_pause = priv->tx_pause ? true : false;
+}
+
+static int cpsw_set_pauseparam(struct net_device *ndev,
+                              struct ethtool_pauseparam *pause)
+{
+       struct cpsw_priv *priv = netdev_priv(ndev);
+       bool link;
+
+       priv->rx_pause = pause->rx_pause ? true : false;
+       priv->tx_pause = pause->tx_pause ? true : false;
+
+       for_each_slave(priv, _cpsw_adjust_link, priv, &link);
+
+       return 0;
+}
+
 static const struct ethtool_ops cpsw_ethtool_ops = {
        .get_drvinfo    = cpsw_get_drvinfo,
        .get_msglevel   = cpsw_get_msglevel,
@@ -1797,6 +1832,8 @@ static const struct ethtool_ops cpsw_ethtool_ops = {
        .get_sset_count         = cpsw_get_sset_count,
        .get_strings            = cpsw_get_strings,
        .get_ethtool_stats      = cpsw_get_ethtool_stats,
+       .get_pauseparam         = cpsw_get_pauseparam,
+       .set_pauseparam         = cpsw_set_pauseparam,
        .get_wol        = cpsw_get_wol,
        .set_wol        = cpsw_set_wol,
        .get_regs_len   = cpsw_get_regs_len,
@@ -2232,18 +2269,24 @@ static int cpsw_probe(struct platform_device *pdev)
        }
 
        while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, k))) {
-               for (i = res->start; i <= res->end; i++) {
-                       if (devm_request_irq(&pdev->dev, i, cpsw_interrupt, 0,
-                                            dev_name(&pdev->dev), priv)) {
-                               dev_err(priv->dev, "error attaching irq\n");
-                               goto clean_ale_ret;
-                       }
-                       priv->irqs_table[k] = i;
-                       priv->num_irqs = k + 1;
+               if (k >= ARRAY_SIZE(priv->irqs_table)) {
+                       ret = -EINVAL;
+                       goto clean_ale_ret;
+               }
+
+               ret = devm_request_irq(&pdev->dev, res->start, cpsw_interrupt,
+                                      0, dev_name(&pdev->dev), priv);
+               if (ret < 0) {
+                       dev_err(priv->dev, "error attaching irq (%d)\n", ret);
+                       goto clean_ale_ret;
                }
+
+               priv->irqs_table[k] = res->start;
                k++;
        }
 
+       priv->num_irqs = k;
+
        ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
 
        ndev->netdev_ops = &cpsw_netdev_ops;
@@ -2353,7 +2396,6 @@ MODULE_DEVICE_TABLE(of, cpsw_of_mtable);
 static struct platform_driver cpsw_driver = {
        .driver = {
                .name    = "cpsw",
-               .owner   = THIS_MODULE,
                .pm      = &cpsw_pm_ops,
                .of_match_table = cpsw_of_mtable,
        },
index 35a139e9a833520a195d16a7c620d423638eb90c..ea712512c7d1f5e155129bf073cac1d7381d38bb 100644 (file)
@@ -2083,7 +2083,6 @@ MODULE_DEVICE_TABLE(of, davinci_emac_of_match);
 static struct platform_driver davinci_emac_driver = {
        .driver = {
                .name    = "davinci_emac",
-               .owner   = THIS_MODULE,
                .pm      = &davinci_emac_pm_ops,
                .of_match_table = of_match_ptr(davinci_emac_of_match),
        },
index 2791f6f2db1178e8f5ce0e0f2a9ecad9f87cffba..98655b44b97e2d7690ef2fa28156730697098d2b 100644 (file)
@@ -481,7 +481,6 @@ MODULE_DEVICE_TABLE(of, davinci_mdio_of_mtable);
 static struct platform_driver davinci_mdio_driver = {
        .driver = {
                .name    = "davinci_mdio",
-               .owner   = THIS_MODULE,
                .pm      = &davinci_mdio_pm_ops,
                .of_match_table = of_match_ptr(davinci_mdio_of_mtable),
        },
index 88c71212669281efe24ba02a783709b2043f8529..88818d5054ab849ee7d6c88fb67faa8aca81f857 100644 (file)
@@ -956,7 +956,7 @@ static int tile_net_open_aux(struct net_device *dev)
         */
        if (hv_dev_pwrite(priv->hv_devhdl, 0, (HV_VirtAddr)&dummy,
                          sizeof(dummy), NETIO_IPP_START_SHIM_OFF) < 0) {
-               pr_warning("Failed to start LIPP/LEPP.\n");
+               pr_warn("Failed to start LIPP/LEPP\n");
                return -EIO;
        }
 
@@ -2399,8 +2399,7 @@ static int __init network_cpus_setup(char *str)
 {
        int rc = cpulist_parse_crop(str, &network_cpus_map);
        if (rc != 0) {
-               pr_warning("network_cpus=%s: malformed cpu list\n",
-                      str);
+               pr_warn("network_cpus=%s: malformed cpu list\n", str);
        } else {
 
                /* Remove dedicated cpus. */
@@ -2409,8 +2408,7 @@ static int __init network_cpus_setup(char *str)
 
 
                if (cpumask_empty(&network_cpus_map)) {
-                       pr_warning("Ignoring network_cpus='%s'.\n",
-                              str);
+                       pr_warn("Ignoring network_cpus='%s'\n", str);
                } else {
                        char buf[1024];
                        cpulist_scnprintf(buf, sizeof(buf), &network_cpus_map);
index c1ba26c06d731252771dfe7f2273b724bc675068..3de2f0d15fe24b22c58a912c1502e7513ad6e6cc 100644 (file)
 #define        PCI_MEM64BIT    (2<<1)       /* Base addr anywhere in 64 Bit range */
 #define        PCI_MEMSPACE    0x00000001L  /* Bit 0:  Memory Space Indic. */
 
-/*     PCI_BASE_2ND    32 bit  2nd Base address */
-#define        PCI_IOBASE      0xffffff00L  /* Bit 31..8:  I/O Base address */
-#define        PCI_IOSIZE      0x000000fcL  /* Bit 7..2:   I/O Size Requirements */
-#define        PCI_IOSPACE     0x00000001L  /* Bit 0:      I/O Space Indicator */
-
 /*     PCI_SUB_VID     16 bit  Subsystem Vendor ID */
 /*     PCI_SUB_ID      16 bit  Subsystem ID */
 
index d5e07def6a598ca3ccb7abda3c80e1732dc64413..2f48f790c9b43e983f44107a97f42f2268262099 100644 (file)
@@ -591,7 +591,7 @@ struct nvsp_message {
 
 #define NETVSC_RECEIVE_BUFFER_ID               0xcafe
 
-#define NETVSC_PACKET_SIZE                      2048
+#define NETVSC_PACKET_SIZE                      4096
 
 #define VRSS_SEND_TAB_SIZE 16
 
@@ -642,7 +642,7 @@ struct netvsc_device {
        int ring_size;
 
        /* The primary channel callback buffer */
-       unsigned char cb_buffer[NETVSC_PACKET_SIZE];
+       unsigned char *cb_buffer;
        /* The sub channel callback buffer */
        unsigned char *sub_cb_buf;
 };
index 66979cf7fca6a3d68d88a7c908c45aad2a7b58aa..977984bc238a1e0cc374c6ef5fd08f07546369d9 100644 (file)
@@ -42,6 +42,12 @@ static struct netvsc_device *alloc_net_device(struct hv_device *device)
        if (!net_device)
                return NULL;
 
+       net_device->cb_buffer = kzalloc(NETVSC_PACKET_SIZE, GFP_KERNEL);
+       if (!net_device->cb_buffer) {
+               kfree(net_device);
+               return NULL;
+       }
+
        init_waitqueue_head(&net_device->wait_drain);
        net_device->start_remove = false;
        net_device->destroy = false;
@@ -52,6 +58,12 @@ static struct netvsc_device *alloc_net_device(struct hv_device *device)
        return net_device;
 }
 
+static void free_netvsc_device(struct netvsc_device *nvdev)
+{
+       kfree(nvdev->cb_buffer);
+       kfree(nvdev);
+}
+
 static struct netvsc_device *get_outbound_net_device(struct hv_device *device)
 {
        struct netvsc_device *net_device;
@@ -551,7 +563,7 @@ int netvsc_device_remove(struct hv_device *device)
        if (net_device->sub_cb_buf)
                vfree(net_device->sub_cb_buf);
 
-       kfree(net_device);
+       free_netvsc_device(net_device);
        return 0;
 }
 
@@ -1042,10 +1054,8 @@ int netvsc_device_add(struct hv_device *device, void *additional_info)
        struct net_device *ndev;
 
        net_device = alloc_net_device(device);
-       if (!net_device) {
-               ret = -ENOMEM;
-               goto cleanup;
-       }
+       if (!net_device)
+               return -ENOMEM;
 
        net_device->ring_size = ring_size;
 
@@ -1093,7 +1103,7 @@ close:
        vmbus_close(device->channel);
 
 cleanup:
-       kfree(net_device);
+       free_netvsc_device(net_device);
 
        return ret;
 }
index a04af9d0f8f93006a1f6425eeb8423c65846a591..a2e556168286649f3c8d809ea8de145fdb7fbad5 100644 (file)
@@ -324,12 +324,8 @@ static void vlsi_proc_ring(struct seq_file *seq, struct vlsi_ring *r)
                seq_printf(seq, "current: rd = %d / status = %02x / len = %u\n",
                                h, (unsigned)rd_get_status(rd), j);
                if (j > 0) {
-                       seq_printf(seq, "   data:");
-                       if (j > 20)
-                               j = 20;
-                       for (i = 0; i < j; i++)
-                               seq_printf(seq, " %02x", (unsigned)((unsigned char *)rd->buf)[i]);
-                       seq_printf(seq, "\n");
+                       seq_printf(seq, "   data: %*ph\n",
+                                  min_t(unsigned, j, 20), rd->buf);
                }
        }
        for (i = 0; i < r->size; i++) {
index 60e4ca01ccbb7d5c2fc26bc8fdcc26a49f943c17..a96955597755326475b5478b974c59ba02c223c7 100644 (file)
@@ -739,7 +739,10 @@ static int macvlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
        struct macvlan_dev *vlan = netdev_priv(dev);
        int err = -EINVAL;
 
-       if (!vlan->port->passthru)
+       /* Support unicast filter only on passthru devices.
+        * Multicast filter should be allowed on all devices.
+        */
+       if (!vlan->port->passthru && is_unicast_ether_addr(addr))
                return -EOPNOTSUPP;
 
        if (flags & NLM_F_REPLACE)
@@ -760,7 +763,10 @@ static int macvlan_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
        struct macvlan_dev *vlan = netdev_priv(dev);
        int err = -EINVAL;
 
-       if (!vlan->port->passthru)
+       /* Support unicast filter only on passthru devices.
+        * Multicast filter should be allowed on all devices.
+        */
+       if (!vlan->port->passthru && is_unicast_ether_addr(addr))
                return -EOPNOTSUPP;
 
        if (is_unicast_ether_addr(addr))
index 65de0cab8d07795c5c2255d7397a95e3720477fc..14afa4f2442427131396e4690cb46d3eceec6c2d 100644 (file)
@@ -159,8 +159,6 @@ config MDIO_OCTEON
 config MDIO_SUN4I
        tristate "Allwinner sun4i MDIO interface support"
        depends on ARCH_SUNXI
-       select REGULATOR
-       select REGULATOR_FIXED_VOLTAGE
        help
          This driver supports the MDIO interface found in the network
          interface units of the Allwinner SoC that have an EMAC (A10,
@@ -205,6 +203,14 @@ config MDIO_BUS_MUX_MMIOREG
 
          Currently, only 8-bit registers are supported.
 
+config MDIO_BCM_UNIMAC
+       tristate "Broadcom UniMAC MDIO bus controller"
+       help
+         This module provides a driver for the Broadcom UniMAC MDIO busses.
+         This hardware can be found in the Broadcom GENET Ethernet MAC
+         controllers as well as some Broadcom Ethernet switches such as the
+         Starfighter 2 switches.
+
 endif # PHYLIB
 
 config MICREL_KS8995MA
index 7dc3d5b304cfc250a2618e096abecf428ed05bad..eb3b18b5978b33ec7441a2ca2e0f4aa33906cdd5 100644 (file)
@@ -34,3 +34,4 @@ obj-$(CONFIG_MDIO_BUS_MUX_MMIOREG) += mdio-mux-mmioreg.o
 obj-$(CONFIG_MDIO_SUN4I)       += mdio-sun4i.o
 obj-$(CONFIG_MDIO_MOXART)      += mdio-moxart.o
 obj-$(CONFIG_AMD_XGBE_PHY)     += amd-xgbe-phy.o
+obj-$(CONFIG_MDIO_BCM_UNIMAC)  += mdio-bcm-unimac.o
index f3230eef41fda7a09442571bb26553ca86b14768..c456559f6e7f2ea3ae713e98c93e58148aaa7776 100644 (file)
@@ -75,7 +75,6 @@
 #include <linux/of_device.h>
 #include <linux/uaccess.h>
 
-
 MODULE_AUTHOR("Tom Lendacky <thomas.lendacky@amd.com>");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_VERSION("1.0.0-a");
@@ -100,9 +99,11 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver");
 #ifndef MDIO_PMA_10GBR_PMD_CTRL
 #define MDIO_PMA_10GBR_PMD_CTRL                0x0096
 #endif
+
 #ifndef MDIO_PMA_10GBR_FEC_CTRL
 #define MDIO_PMA_10GBR_FEC_CTRL                0x00ab
 #endif
+
 #ifndef MDIO_AN_XNP
 #define MDIO_AN_XNP                    0x0016
 #endif
@@ -110,14 +111,23 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver");
 #ifndef MDIO_AN_INTMASK
 #define MDIO_AN_INTMASK                        0x8001
 #endif
+
 #ifndef MDIO_AN_INT
 #define MDIO_AN_INT                    0x8002
 #endif
 
+#ifndef MDIO_AN_KR_CTRL
+#define MDIO_AN_KR_CTRL                        0x8003
+#endif
+
 #ifndef MDIO_CTRL1_SPEED1G
 #define MDIO_CTRL1_SPEED1G             (MDIO_CTRL1_SPEED10G & ~BMCR_SPEED100)
 #endif
 
+#ifndef MDIO_KR_CTRL_PDETECT
+#define MDIO_KR_CTRL_PDETECT           0x01
+#endif
+
 /* SerDes integration register offsets */
 #define SIR0_KR_RT_1                   0x002c
 #define SIR0_STATUS                    0x0040
@@ -161,7 +171,6 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver");
 #define SPEED_1000_TXAMP               0xf
 #define SPEED_1000_WORD                        0x1
 
-
 /* SerDes RxTx register offsets */
 #define RXTX_REG20                     0x0050
 #define RXTX_REG114                    0x01c8
@@ -255,7 +264,6 @@ do {                                                                        \
        XSIR1_IOWRITE((_priv), _reg, reg_val);                          \
 } while (0)
 
-
 /* Macros for reading or writing SerDes RxTx registers
  *  The ioread macros will get bit fields or full values using the
  *  register definitions formed using the input names
@@ -283,7 +291,6 @@ do {                                                                        \
        XRXTX_IOWRITE((_priv), _reg, reg_val);                          \
 } while (0)
 
-
 enum amd_xgbe_phy_an {
        AMD_XGBE_AN_READY = 0,
        AMD_XGBE_AN_START,
@@ -331,7 +338,6 @@ struct amd_xgbe_phy_priv {
 
        /* Maintain link status for re-starting auto-negotiation */
        unsigned int link;
-       enum amd_xgbe_phy_mode mode;
        unsigned int speed_set;
 
        /* Auto-negotiation state machine support */
@@ -342,6 +348,7 @@ struct amd_xgbe_phy_priv {
        enum amd_xgbe_phy_rx kx_state;
        struct work_struct an_work;
        struct workqueue_struct *an_workqueue;
+       unsigned int parallel_detect;
 };
 
 static int amd_xgbe_an_enable_kr_training(struct phy_device *phydev)
@@ -468,8 +475,6 @@ static int amd_xgbe_phy_xgmii_mode(struct phy_device *phydev)
 
        amd_xgbe_phy_serdes_complete_ratechange(phydev);
 
-       priv->mode = AMD_XGBE_MODE_KR;
-
        return 0;
 }
 
@@ -518,8 +523,6 @@ static int amd_xgbe_phy_gmii_2500_mode(struct phy_device *phydev)
 
        amd_xgbe_phy_serdes_complete_ratechange(phydev);
 
-       priv->mode = AMD_XGBE_MODE_KX;
-
        return 0;
 }
 
@@ -568,18 +571,43 @@ static int amd_xgbe_phy_gmii_mode(struct phy_device *phydev)
 
        amd_xgbe_phy_serdes_complete_ratechange(phydev);
 
-       priv->mode = AMD_XGBE_MODE_KX;
+       return 0;
+}
+
+static int amd_xgbe_phy_cur_mode(struct phy_device *phydev,
+                                enum amd_xgbe_phy_mode *mode)
+{
+       int ret;
+
+       ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2);
+       if (ret < 0)
+               return ret;
+
+       if ((ret & MDIO_PCS_CTRL2_TYPE) == MDIO_PCS_CTRL2_10GBR)
+               *mode = AMD_XGBE_MODE_KR;
+       else
+               *mode = AMD_XGBE_MODE_KX;
 
        return 0;
 }
 
+static bool amd_xgbe_phy_in_kr_mode(struct phy_device *phydev)
+{
+       enum amd_xgbe_phy_mode mode;
+
+       if (amd_xgbe_phy_cur_mode(phydev, &mode))
+               return false;
+
+       return (mode == AMD_XGBE_MODE_KR);
+}
+
 static int amd_xgbe_phy_switch_mode(struct phy_device *phydev)
 {
        struct amd_xgbe_phy_priv *priv = phydev->priv;
        int ret;
 
        /* If we are in KR switch to KX, and vice-versa */
-       if (priv->mode == AMD_XGBE_MODE_KR) {
+       if (amd_xgbe_phy_in_kr_mode(phydev)) {
                if (priv->speed_set == AMD_XGBE_PHY_SPEEDSET_1000_10000)
                        ret = amd_xgbe_phy_gmii_mode(phydev);
                else
@@ -591,15 +619,20 @@ static int amd_xgbe_phy_switch_mode(struct phy_device *phydev)
        return ret;
 }
 
-static enum amd_xgbe_phy_an amd_xgbe_an_switch_mode(struct phy_device *phydev)
+static int amd_xgbe_phy_set_mode(struct phy_device *phydev,
+                                enum amd_xgbe_phy_mode mode)
 {
+       enum amd_xgbe_phy_mode cur_mode;
        int ret;
 
-       ret = amd_xgbe_phy_switch_mode(phydev);
-       if (ret < 0)
-               return AMD_XGBE_AN_ERROR;
+       ret = amd_xgbe_phy_cur_mode(phydev, &cur_mode);
+       if (ret)
+               return ret;
 
-       return AMD_XGBE_AN_START;
+       if (mode != cur_mode)
+               ret = amd_xgbe_phy_switch_mode(phydev);
+
+       return ret;
 }
 
 static enum amd_xgbe_phy_an amd_xgbe_an_tx_training(struct phy_device *phydev,
@@ -610,8 +643,8 @@ static enum amd_xgbe_phy_an amd_xgbe_an_tx_training(struct phy_device *phydev,
 
        *state = AMD_XGBE_RX_COMPLETE;
 
-       /* If we're in KX mode then we're done */
-       if (priv->mode == AMD_XGBE_MODE_KX)
+       /* If we're not in KR mode then we're done */
+       if (!amd_xgbe_phy_in_kr_mode(phydev))
                return AMD_XGBE_AN_EVENT;
 
        /* Enable/Disable FEC */
@@ -669,7 +702,6 @@ static enum amd_xgbe_phy_an amd_xgbe_an_tx_xnp(struct phy_device *phydev,
 static enum amd_xgbe_phy_an amd_xgbe_an_rx_bpa(struct phy_device *phydev,
                                               enum amd_xgbe_phy_rx *state)
 {
-       struct amd_xgbe_phy_priv *priv = phydev->priv;
        unsigned int link_support;
        int ret, ad_reg, lp_reg;
 
@@ -679,9 +711,9 @@ static enum amd_xgbe_phy_an amd_xgbe_an_rx_bpa(struct phy_device *phydev,
                return AMD_XGBE_AN_ERROR;
 
        /* Check for a supported mode, otherwise restart in a different one */
-       link_support = (priv->mode == AMD_XGBE_MODE_KR) ? 0x80 : 0x20;
+       link_support = amd_xgbe_phy_in_kr_mode(phydev) ? 0x80 : 0x20;
        if (!(ret & link_support))
-               return amd_xgbe_an_switch_mode(phydev);
+               return AMD_XGBE_AN_INCOMPAT_LINK;
 
        /* Check Extended Next Page support */
        ad_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
@@ -722,7 +754,7 @@ static enum amd_xgbe_phy_an amd_xgbe_an_start(struct phy_device *phydev)
        int ret;
 
        /* Be sure we aren't looping trying to negotiate */
-       if (priv->mode == AMD_XGBE_MODE_KR) {
+       if (amd_xgbe_phy_in_kr_mode(phydev)) {
                if (priv->kr_state != AMD_XGBE_RX_READY)
                        return AMD_XGBE_AN_NO_LINK;
                priv->kr_state = AMD_XGBE_RX_BPA;
@@ -785,6 +817,13 @@ static enum amd_xgbe_phy_an amd_xgbe_an_start(struct phy_device *phydev)
        /* Enable and start auto-negotiation */
        phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0);
 
+       ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_KR_CTRL);
+       if (ret < 0)
+               return AMD_XGBE_AN_ERROR;
+
+       ret |= MDIO_KR_CTRL_PDETECT;
+       phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_KR_CTRL, ret);
+
        ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1);
        if (ret < 0)
                return AMD_XGBE_AN_ERROR;
@@ -825,8 +864,8 @@ static enum amd_xgbe_phy_an amd_xgbe_an_page_received(struct phy_device *phydev)
        enum amd_xgbe_phy_rx *state;
        int ret;
 
-       state = (priv->mode == AMD_XGBE_MODE_KR) ? &priv->kr_state
-                                                : &priv->kx_state;
+       state = amd_xgbe_phy_in_kr_mode(phydev) ? &priv->kr_state
+                                               : &priv->kx_state;
 
        switch (*state) {
        case AMD_XGBE_RX_BPA:
@@ -846,7 +885,13 @@ static enum amd_xgbe_phy_an amd_xgbe_an_page_received(struct phy_device *phydev)
 
 static enum amd_xgbe_phy_an amd_xgbe_an_incompat_link(struct phy_device *phydev)
 {
-       return amd_xgbe_an_switch_mode(phydev);
+       int ret;
+
+       ret = amd_xgbe_phy_switch_mode(phydev);
+       if (ret)
+               return AMD_XGBE_AN_ERROR;
+
+       return AMD_XGBE_AN_START;
 }
 
 static void amd_xgbe_an_state_machine(struct work_struct *work)
@@ -859,6 +904,10 @@ static void amd_xgbe_an_state_machine(struct work_struct *work)
        int sleep;
        unsigned int an_supported = 0;
 
+       /* Start in KX mode */
+       if (amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KX))
+               priv->an_state = AMD_XGBE_AN_ERROR;
+
        while (1) {
                mutex_lock(&priv->an_mutex);
 
@@ -866,8 +915,9 @@ static void amd_xgbe_an_state_machine(struct work_struct *work)
 
                switch (priv->an_state) {
                case AMD_XGBE_AN_START:
-                       priv->an_state = amd_xgbe_an_start(phydev);
                        an_supported = 0;
+                       priv->parallel_detect = 0;
+                       priv->an_state = amd_xgbe_an_start(phydev);
                        break;
 
                case AMD_XGBE_AN_EVENT:
@@ -884,6 +934,7 @@ static void amd_xgbe_an_state_machine(struct work_struct *work)
                        break;
 
                case AMD_XGBE_AN_COMPLETE:
+                       priv->parallel_detect = an_supported ? 0 : 1;
                        netdev_info(phydev->attached_dev, "%s successful\n",
                                    an_supported ? "Auto negotiation"
                                                 : "Parallel detection");
@@ -1018,7 +1069,6 @@ static int amd_xgbe_phy_config_aneg(struct phy_device *phydev)
 {
        struct amd_xgbe_phy_priv *priv = phydev->priv;
        u32 mmd_mask = phydev->c45_ids.devices_in_package;
-       int ret;
 
        if (phydev->autoneg != AUTONEG_ENABLE)
                return amd_xgbe_phy_setup_forced(phydev);
@@ -1027,11 +1077,6 @@ static int amd_xgbe_phy_config_aneg(struct phy_device *phydev)
        if (!(mmd_mask & MDIO_DEVS_AN))
                return -EINVAL;
 
-       /* Get the current speed mode */
-       ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2);
-       if (ret < 0)
-               return ret;
-
        /* Start/Restart the auto-negotiation state machine */
        mutex_lock(&priv->an_mutex);
        priv->an_result = AMD_XGBE_AN_READY;
@@ -1121,18 +1166,14 @@ static int amd_xgbe_phy_read_status(struct phy_device *phydev)
 {
        struct amd_xgbe_phy_priv *priv = phydev->priv;
        u32 mmd_mask = phydev->c45_ids.devices_in_package;
-       int ret, mode, ad_ret, lp_ret;
+       int ret, ad_ret, lp_ret;
 
        ret = amd_xgbe_phy_update_link(phydev);
        if (ret)
                return ret;
 
-       mode = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2);
-       if (mode < 0)
-               return mode;
-       mode &= MDIO_PCS_CTRL2_TYPE;
-
-       if (phydev->autoneg == AUTONEG_ENABLE) {
+       if ((phydev->autoneg == AUTONEG_ENABLE) &&
+           !priv->parallel_detect) {
                if (!(mmd_mask & MDIO_DEVS_AN))
                        return -EINVAL;
 
@@ -1163,40 +1204,39 @@ static int amd_xgbe_phy_read_status(struct phy_device *phydev)
                ad_ret &= lp_ret;
                if (ad_ret & 0x80) {
                        phydev->speed = SPEED_10000;
-                       if (mode != MDIO_PCS_CTRL2_10GBR) {
-                               ret = amd_xgbe_phy_xgmii_mode(phydev);
-                               if (ret < 0)
-                                       return ret;
-                       }
+                       ret = amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KR);
+                       if (ret)
+                               return ret;
                } else {
-                       int (*mode_fcn)(struct phy_device *);
-
-                       if (priv->speed_set ==
-                           AMD_XGBE_PHY_SPEEDSET_1000_10000) {
+                       switch (priv->speed_set) {
+                       case AMD_XGBE_PHY_SPEEDSET_1000_10000:
                                phydev->speed = SPEED_1000;
-                               mode_fcn = amd_xgbe_phy_gmii_mode;
-                       } else {
+                               break;
+
+                       case AMD_XGBE_PHY_SPEEDSET_2500_10000:
                                phydev->speed = SPEED_2500;
-                               mode_fcn = amd_xgbe_phy_gmii_2500_mode;
+                               break;
                        }
 
-                       if (mode == MDIO_PCS_CTRL2_10GBR) {
-                               ret = mode_fcn(phydev);
-                               if (ret < 0)
-                                       return ret;
-                       }
+                       ret = amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KX);
+                       if (ret)
+                               return ret;
                }
 
                phydev->duplex = DUPLEX_FULL;
        } else {
-               if (mode == MDIO_PCS_CTRL2_10GBR) {
+               if (amd_xgbe_phy_in_kr_mode(phydev)) {
                        phydev->speed = SPEED_10000;
                } else {
-                       if (priv->speed_set ==
-                           AMD_XGBE_PHY_SPEEDSET_1000_10000)
+                       switch (priv->speed_set) {
+                       case AMD_XGBE_PHY_SPEEDSET_1000_10000:
                                phydev->speed = SPEED_1000;
-                       else
+                               break;
+
+                       case AMD_XGBE_PHY_SPEEDSET_2500_10000:
                                phydev->speed = SPEED_2500;
+                               break;
+                       }
                }
                phydev->duplex = DUPLEX_FULL;
                phydev->pause = 0;
@@ -1329,14 +1369,6 @@ static int amd_xgbe_phy_probe(struct phy_device *phydev)
 
        priv->link = 1;
 
-       ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL2);
-       if (ret < 0)
-               goto err_sir1;
-       if ((ret & MDIO_PCS_CTRL2_TYPE) == MDIO_PCS_CTRL2_10GBR)
-               priv->mode = AMD_XGBE_MODE_KR;
-       else
-               priv->mode = AMD_XGBE_MODE_KX;
-
        mutex_init(&priv->an_mutex);
        INIT_WORK(&priv->an_work, amd_xgbe_an_state_machine);
        priv->an_workqueue = create_singlethread_workqueue(wq_name);
index 526b94cea56980633c1d78caabac13004211766f..09dd6e1dc6e12ccb59a6640bc97b2fb5116dd768 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/delay.h>
 #include <linux/bitops.h>
 #include <linux/brcmphy.h>
+#include <linux/mdio.h>
 
 /* Broadcom BCM7xxx internal PHY registers */
 #define MII_BCM7XXX_CHANNEL_WIDTH      0x2000
@@ -146,6 +147,53 @@ static int bcm7xxx_28nm_afe_config_init(struct phy_device *phydev)
        return 0;
 }
 
+static int bcm7xxx_apd_enable(struct phy_device *phydev)
+{
+       int val;
+
+       /* Enable powering down of the DLL during auto-power down */
+       val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_SCR3);
+       if (val < 0)
+               return val;
+
+       val |= BCM54XX_SHD_SCR3_DLLAPD_DIS;
+       bcm54xx_shadow_write(phydev, BCM54XX_SHD_SCR3, val);
+
+       /* Enable auto-power down */
+       val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_APD);
+       if (val < 0)
+               return val;
+
+       val |= BCM54XX_SHD_APD_EN;
+       return bcm54xx_shadow_write(phydev, BCM54XX_SHD_APD, val);
+}
+
+static int bcm7xxx_eee_enable(struct phy_device *phydev)
+{
+       int val;
+
+       val = phy_read_mmd_indirect(phydev, BRCM_CL45VEN_EEE_CONTROL,
+                                   MDIO_MMD_AN, phydev->addr);
+       if (val < 0)
+               return val;
+
+       /* Enable general EEE feature at the PHY level */
+       val |= LPI_FEATURE_EN | LPI_FEATURE_EN_DIG1000X;
+
+       phy_write_mmd_indirect(phydev, BRCM_CL45VEN_EEE_CONTROL,
+                              MDIO_MMD_AN, phydev->addr, val);
+
+       /* Advertise supported modes */
+       val = phy_read_mmd_indirect(phydev, MDIO_AN_EEE_ADV,
+                                   MDIO_MMD_AN, phydev->addr);
+
+       val |= (MDIO_AN_EEE_ADV_100TX | MDIO_AN_EEE_ADV_1000T);
+       phy_write_mmd_indirect(phydev, MDIO_AN_EEE_ADV,
+                              MDIO_MMD_AN, phydev->addr, val);
+
+       return 0;
+}
+
 static int bcm7xxx_28nm_config_init(struct phy_device *phydev)
 {
        int ret;
@@ -154,7 +202,32 @@ static int bcm7xxx_28nm_config_init(struct phy_device *phydev)
        if (ret)
                return ret;
 
-       return bcm7xxx_28nm_afe_config_init(phydev);
+       ret = bcm7xxx_28nm_afe_config_init(phydev);
+       if (ret)
+               return ret;
+
+       ret = bcm7xxx_eee_enable(phydev);
+       if (ret)
+               return ret;
+
+       return bcm7xxx_apd_enable(phydev);
+}
+
+static int bcm7xxx_28nm_resume(struct phy_device *phydev)
+{
+       int ret;
+
+       /* Re-apply workarounds coming out suspend/resume */
+       ret = bcm7xxx_28nm_config_init(phydev);
+       if (ret)
+               return ret;
+
+       /* 28nm Gigabit PHYs come out of reset without any half-duplex
+        * or "hub" compliant advertised mode, fix that. This does not
+        * cause any problems with the PHY library since genphy_config_aneg()
+        * gracefully handles auto-negotiated and forced modes.
+        */
+       return genphy_config_aneg(phydev);
 }
 
 static int phy_set_clr_bits(struct phy_device *dev, int location,
@@ -212,7 +285,7 @@ static int bcm7xxx_config_init(struct phy_device *phydev)
 }
 
 /* Workaround for putting the PHY in IDDQ mode, required
- * for all BCM7XXX PHYs
+ * for all BCM7XXX 40nm and 65nm PHYs
  */
 static int bcm7xxx_suspend(struct phy_device *phydev)
 {
@@ -246,60 +319,28 @@ static int bcm7xxx_dummy_config_init(struct phy_device *phydev)
        return 0;
 }
 
+#define BCM7XXX_28NM_GPHY(_oui, _name)                                 \
+{                                                                      \
+       .phy_id         = (_oui),                                       \
+       .phy_id_mask    = 0xfffffff0,                                   \
+       .name           = _name,                                        \
+       .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,                           \
+       .resume         = bcm7xxx_28nm_resume,                          \
+       .driver         = { .owner = THIS_MODULE },                     \
+}
+
 static struct phy_driver bcm7xxx_driver[] = {
+       BCM7XXX_28NM_GPHY(PHY_ID_BCM7250, "Broadcom BCM7250"),
+       BCM7XXX_28NM_GPHY(PHY_ID_BCM7364, "Broadcom BCM7364"),
+       BCM7XXX_28NM_GPHY(PHY_ID_BCM7366, "Broadcom BCM7366"),
+       BCM7XXX_28NM_GPHY(PHY_ID_BCM7439, "Broadcom BCM7439"),
+       BCM7XXX_28NM_GPHY(PHY_ID_BCM7445, "Broadcom BCM7445"),
 {
-       .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",
@@ -328,10 +369,11 @@ static struct phy_driver bcm7xxx_driver[] = {
 } };
 
 static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = {
+       { PHY_ID_BCM7250, 0xfffffff0, },
+       { PHY_ID_BCM7364, 0xfffffff0, },
        { 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 },
        { }
index 34088d60da74613cd007916ddd4844ee5420f90a..854f2c9a7b2b5224f1dab808d16d8f514cdd486a 100644 (file)
 #define BRCM_PHY_REV(phydev) \
        ((phydev)->drv->phy_id & ~((phydev)->drv->phy_id_mask))
 
-/*
- * Broadcom LED source encodings.  These are used in BCM5461, BCM5481,
- * BCM5482, and possibly some others.
- */
-#define BCM_LED_SRC_LINKSPD1   0x0
-#define BCM_LED_SRC_LINKSPD2   0x1
-#define BCM_LED_SRC_XMITLED    0x2
-#define BCM_LED_SRC_ACTIVITYLED        0x3
-#define BCM_LED_SRC_FDXLED     0x4
-#define BCM_LED_SRC_SLAVE      0x5
-#define BCM_LED_SRC_INTR       0x6
-#define BCM_LED_SRC_QUALITY    0x7
-#define BCM_LED_SRC_RCVLED     0x8
-#define BCM_LED_SRC_MULTICOLOR1        0xa
-#define BCM_LED_SRC_OPENSHORT  0xb
-#define BCM_LED_SRC_OFF                0xe     /* Tied high */
-#define BCM_LED_SRC_ON         0xf     /* Tied low */
-
-
-/*
- * BCM5482: Shadow registers
- * Shadow values go into bits [14:10] of register 0x1c to select a shadow
- * register to access.
- */
-/* 00101: Spare Control Register 3 */
-#define BCM54XX_SHD_SCR3               0x05
-#define  BCM54XX_SHD_SCR3_DEF_CLK125   0x0001
-#define  BCM54XX_SHD_SCR3_DLLAPD_DIS   0x0002
-#define  BCM54XX_SHD_SCR3_TRDDAPD      0x0004
-
-/* 01010: Auto Power-Down */
-#define BCM54XX_SHD_APD                        0x0a
-#define  BCM54XX_SHD_APD_EN            0x0020
-
-#define BCM5482_SHD_LEDS1      0x0d    /* 01101: LED Selector 1 */
-                                       /* LED3 / ~LINKSPD[2] selector */
-#define BCM5482_SHD_LEDS1_LED3(src)    ((src & 0xf) << 4)
-                                       /* LED1 / ~LINKSPD[1] selector */
-#define BCM5482_SHD_LEDS1_LED1(src)    ((src & 0xf) << 0)
-#define BCM54XX_SHD_RGMII_MODE 0x0b    /* 01011: RGMII Mode Selector */
-#define BCM5482_SHD_SSD                0x14    /* 10100: Secondary SerDes control */
-#define BCM5482_SHD_SSD_LEDM   0x0008  /* SSD LED Mode enable */
-#define BCM5482_SHD_SSD_EN     0x0001  /* SSD enable */
-#define BCM5482_SHD_MODE       0x1f    /* 11111: Mode Control Register */
-#define BCM5482_SHD_MODE_1000BX        0x0001  /* Enable 1000BASE-X registers */
-
-
-/*
- * EXPANSION SHADOW ACCESS REGISTERS.  (PHY REG 0x15, 0x16, and 0x17)
- */
-#define MII_BCM54XX_EXP_AADJ1CH0               0x001f
-#define  MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN 0x0200
-#define  MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF   0x0100
-#define MII_BCM54XX_EXP_AADJ1CH3               0x601f
-#define  MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ     0x0002
-#define MII_BCM54XX_EXP_EXP08                  0x0F08
-#define  MII_BCM54XX_EXP_EXP08_RJCT_2MHZ       0x0001
-#define  MII_BCM54XX_EXP_EXP08_EARLY_DAC_WAKE  0x0200
-#define MII_BCM54XX_EXP_EXP75                  0x0f75
-#define  MII_BCM54XX_EXP_EXP75_VDACCTRL                0x003c
-#define  MII_BCM54XX_EXP_EXP75_CM_OSC          0x0001
-#define MII_BCM54XX_EXP_EXP96                  0x0f96
-#define  MII_BCM54XX_EXP_EXP96_MYST            0x0010
-#define MII_BCM54XX_EXP_EXP97                  0x0f97
-#define  MII_BCM54XX_EXP_EXP97_MYST            0x0c0c
-
-/*
- * BCM5482: Secondary SerDes registers
- */
-#define BCM5482_SSD_1000BX_CTL         0x00    /* 1000BASE-X Control */
-#define BCM5482_SSD_1000BX_CTL_PWRDOWN 0x0800  /* Power-down SSD */
-#define BCM5482_SSD_SGMII_SLAVE                0x15    /* SGMII Slave Register */
-#define BCM5482_SSD_SGMII_SLAVE_EN     0x0002  /* Slave mode enable */
-#define BCM5482_SSD_SGMII_SLAVE_AD     0x0001  /* Slave auto-detection */
-
-
-/*****************************************************************************/
-/* Fast Ethernet Transceiver definitions. */
-/*****************************************************************************/
-
-#define MII_BRCM_FET_INTREG            0x1a    /* Interrupt register */
-#define MII_BRCM_FET_IR_MASK           0x0100  /* Mask all interrupts */
-#define MII_BRCM_FET_IR_LINK_EN                0x0200  /* Link status change enable */
-#define MII_BRCM_FET_IR_SPEED_EN       0x0400  /* Link speed change enable */
-#define MII_BRCM_FET_IR_DUPLEX_EN      0x0800  /* Duplex mode change enable */
-#define MII_BRCM_FET_IR_ENABLE         0x4000  /* Interrupt enable */
-
-#define MII_BRCM_FET_BRCMTEST          0x1f    /* Brcm test register */
-#define MII_BRCM_FET_BT_SRE            0x0080  /* Shadow register enable */
-
-
-/*** Shadow register definitions ***/
-
-#define MII_BRCM_FET_SHDW_MISCCTRL     0x10    /* Shadow misc ctrl */
-#define MII_BRCM_FET_SHDW_MC_FAME      0x4000  /* Force Auto MDIX enable */
-
-#define MII_BRCM_FET_SHDW_AUXMODE4     0x1a    /* Auxiliary mode 4 */
-#define MII_BRCM_FET_SHDW_AM4_LED_MASK 0x0003
-#define MII_BRCM_FET_SHDW_AM4_LED_MODE1 0x0001
-
-#define MII_BRCM_FET_SHDW_AUXSTAT2     0x1b    /* Auxiliary status 2 */
-#define MII_BRCM_FET_SHDW_AS2_APDE     0x0020  /* Auto power down enable */
-
-
 MODULE_DESCRIPTION("Broadcom PHY driver");
 MODULE_AUTHOR("Maciej W. Rozycki");
 MODULE_LICENSE("GPL");
 
-/*
- * Indirect register access functions for the 1000BASE-T/100BASE-TX/10BASE-T
- * 0x1c shadow registers.
- */
-static int bcm54xx_shadow_read(struct phy_device *phydev, u16 shadow)
-{
-       phy_write(phydev, MII_BCM54XX_SHD, MII_BCM54XX_SHD_VAL(shadow));
-       return MII_BCM54XX_SHD_DATA(phy_read(phydev, MII_BCM54XX_SHD));
-}
-
-static int bcm54xx_shadow_write(struct phy_device *phydev, u16 shadow, u16 val)
-{
-       return phy_write(phydev, MII_BCM54XX_SHD,
-                        MII_BCM54XX_SHD_WRITE |
-                        MII_BCM54XX_SHD_VAL(shadow) |
-                        MII_BCM54XX_SHD_DATA(val));
-}
-
 /* Indirect register access functions for the Expansion Registers */
 static int bcm54xx_exp_read(struct phy_device *phydev, u16 regnum)
 {
index c301e4cb37cacc3b77645afb265871242abac37a..2954052706e8bcbf0979e89772326656ba6c57fa 100644 (file)
@@ -721,7 +721,7 @@ static inline u16 exts_chan_to_edata(int ch)
 }
 
 static int decode_evnt(struct dp83640_private *dp83640,
-                      void *data, u16 ests)
+                      void *data, int len, u16 ests)
 {
        struct phy_txts *phy_txts;
        struct ptp_clock_event event;
@@ -729,6 +729,16 @@ static int decode_evnt(struct dp83640_private *dp83640,
        int words = (ests >> EVNT_TS_LEN_SHIFT) & EVNT_TS_LEN_MASK;
        u16 ext_status = 0;
 
+       /* calculate length of the event timestamp status message */
+       if (ests & MULT_EVNT)
+               parsed = (words + 2) * sizeof(u16);
+       else
+               parsed = (words + 1) * sizeof(u16);
+
+       /* check if enough data is available */
+       if (len < parsed)
+               return len;
+
        if (ests & MULT_EVNT) {
                ext_status = *(u16 *) data;
                data += sizeof(ext_status);
@@ -747,10 +757,7 @@ static int decode_evnt(struct dp83640_private *dp83640,
                dp83640->edata.ns_lo = phy_txts->ns_lo;
        }
 
-       if (ext_status) {
-               parsed = words + 2;
-       } else {
-               parsed = words + 1;
+       if (!ext_status) {
                i = ((ests >> EVNT_NUM_SHIFT) & EVNT_NUM_MASK) - EXT_EVENT;
                ext_status = exts_chan_to_edata(i);
        }
@@ -768,7 +775,7 @@ static int decode_evnt(struct dp83640_private *dp83640,
                }
        }
 
-       return parsed * sizeof(u16);
+       return parsed;
 }
 
 static int match(struct sk_buff *skb, unsigned int type, struct rxts *rxts)
@@ -905,9 +912,9 @@ static void decode_status_frame(struct dp83640_private *dp83640,
                        decode_txts(dp83640, phy_txts);
                        size = sizeof(*phy_txts);
 
-               } else if (PSF_EVNT == type && len >= sizeof(*phy_txts)) {
+               } else if (PSF_EVNT == type) {
 
-                       size = decode_evnt(dp83640, ptr, ests);
+                       size = decode_evnt(dp83640, ptr, len, ests);
 
                } else {
                        size = 0;
@@ -1129,7 +1136,6 @@ static void dp83640_remove(struct phy_device *phydev)
        struct dp83640_clock *clock;
        struct list_head *this, *next;
        struct dp83640_private *tmp, *dp83640 = phydev->priv;
-       struct sk_buff *skb;
 
        if (phydev->addr == BROADCAST_ADDR)
                return;
@@ -1137,11 +1143,8 @@ static void dp83640_remove(struct phy_device *phydev)
        enable_status_frames(phydev, false);
        cancel_work_sync(&dp83640->ts_work);
 
-       while ((skb = skb_dequeue(&dp83640->rx_queue)) != NULL)
-               kfree_skb(skb);
-
-       while ((skb = skb_dequeue(&dp83640->tx_queue)) != NULL)
-               skb_complete_tx_timestamp(skb, NULL);
+       skb_queue_purge(&dp83640->rx_queue);
+       skb_queue_purge(&dp83640->tx_queue);
 
        clock = dp83640_clock_get(dp83640->clock);
 
@@ -1398,7 +1401,7 @@ static void dp83640_txtstamp(struct phy_device *phydev,
 
        case HWTSTAMP_TX_ONESTEP_SYNC:
                if (is_sync(skb, type)) {
-                       skb_complete_tx_timestamp(skb, NULL);
+                       kfree_skb(skb);
                        return;
                }
                /* fall through */
@@ -1409,7 +1412,7 @@ static void dp83640_txtstamp(struct phy_device *phydev,
 
        case HWTSTAMP_TX_OFF:
        default:
-               skb_complete_tx_timestamp(skb, NULL);
+               kfree_skb(skb);
                break;
        }
 }
index d60d875cb4450ab6cf72114c35b4c816e2e031fd..5b19fbbda6d4fd4e2826d873470b60197017999f 100644 (file)
@@ -124,6 +124,17 @@ static int fixed_mdio_read(struct mii_bus *bus, int phy_addr, int reg_num)
        if (reg_num >= MII_REGS_NUM)
                return -1;
 
+       /* We do not support emulating Clause 45 over Clause 22 register reads
+        * return an error instead of bogus data.
+        */
+       switch (reg_num) {
+       case MII_MMD_CTRL:
+       case MII_MMD_DATA:
+               return -1;
+       default:
+               break;
+       }
+
        list_for_each_entry(fp, &fmb->phys, node) {
                if (fp->addr == phy_addr) {
                        /* Issue callback if user registered it. */
diff --git a/drivers/net/phy/mdio-bcm-unimac.c b/drivers/net/phy/mdio-bcm-unimac.c
new file mode 100644 (file)
index 0000000..5b643e5
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * Broadcom UniMAC MDIO bus 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 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/phy.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_mdio.h>
+
+#define MDIO_CMD               0x00
+#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 MDIO_CFG               0x04
+#define  MDIO_C22              (1 << 0)
+#define  MDIO_C45              0
+#define  MDIO_CLK_DIV_SHIFT    4
+#define  MDIO_CLK_DIV_MASK     0x3F
+#define  MDIO_SUPP_PREAMBLE    (1 << 12)
+
+struct unimac_mdio_priv {
+       struct mii_bus          *mii_bus;
+       void __iomem            *base;
+};
+
+static inline void unimac_mdio_start(struct unimac_mdio_priv *priv)
+{
+       u32 reg;
+
+       reg = __raw_readl(priv->base + MDIO_CMD);
+       reg |= MDIO_START_BUSY;
+       __raw_writel(reg, priv->base + MDIO_CMD);
+}
+
+static inline unsigned int unimac_mdio_busy(struct unimac_mdio_priv *priv)
+{
+       return __raw_readl(priv->base + MDIO_CMD) & MDIO_START_BUSY;
+}
+
+static int unimac_mdio_read(struct mii_bus *bus, int phy_id, int reg)
+{
+       struct unimac_mdio_priv *priv = bus->priv;
+       unsigned int timeout = 1000;
+       u32 cmd;
+
+       /* Prepare the read operation */
+       cmd = MDIO_RD | (phy_id << MDIO_PMD_SHIFT) | (reg << MDIO_REG_SHIFT);
+       __raw_writel(cmd, priv->base + MDIO_CMD);
+
+       /* Start MDIO transaction */
+       unimac_mdio_start(priv);
+
+       do {
+               if (!unimac_mdio_busy(priv))
+                       break;
+
+               usleep_range(1000, 2000);
+       } while (timeout--);
+
+       if (!timeout)
+               return -ETIMEDOUT;
+
+       cmd = __raw_readl(priv->base + MDIO_CMD);
+       if (cmd & MDIO_READ_FAIL)
+               return -EIO;
+
+       return cmd & 0xffff;
+}
+
+static int unimac_mdio_write(struct mii_bus *bus, int phy_id,
+                            int reg, u16 val)
+{
+       struct unimac_mdio_priv *priv = bus->priv;
+       unsigned int timeout = 1000;
+       u32 cmd;
+
+       /* Prepare the write operation */
+       cmd = MDIO_WR | (phy_id << MDIO_PMD_SHIFT) |
+               (reg << MDIO_REG_SHIFT) | (0xffff & val);
+       __raw_writel(cmd, priv->base + MDIO_CMD);
+
+       unimac_mdio_start(priv);
+
+       do {
+               if (!unimac_mdio_busy(priv))
+                       break;
+
+               usleep_range(1000, 2000);
+       } while (timeout--);
+
+       if (!timeout)
+               return -ETIMEDOUT;
+
+       return 0;
+}
+
+static int unimac_mdio_probe(struct platform_device *pdev)
+{
+       struct unimac_mdio_priv *priv;
+       struct device_node *np;
+       struct mii_bus *bus;
+       struct resource *r;
+       int ret;
+
+       np = pdev->dev.of_node;
+
+       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       /* Just ioremap, as this MDIO block is usually integrated into an
+        * Ethernet MAC controller register range
+        */
+       priv->base = devm_ioremap(&pdev->dev, r->start, resource_size(r));
+       if (!priv->base) {
+               dev_err(&pdev->dev, "failed to remap register\n");
+               return -ENOMEM;
+       }
+
+       priv->mii_bus = mdiobus_alloc();
+       if (!priv->mii_bus)
+               return -ENOMEM;
+
+       bus = priv->mii_bus;
+       bus->priv = priv;
+       bus->name = "unimac MII bus";
+       bus->parent = &pdev->dev;
+       bus->read = unimac_mdio_read;
+       bus->write = unimac_mdio_write;
+       snprintf(bus->id, MII_BUS_ID_SIZE, "%s", pdev->name);
+
+       bus->irq = kcalloc(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL);
+       if (!bus->irq) {
+               ret = -ENOMEM;
+               goto out_mdio_free;
+       }
+
+       ret = of_mdiobus_register(bus, np);
+       if (ret) {
+               dev_err(&pdev->dev, "MDIO bus registration failed\n");
+               goto out_mdio_irq;
+       }
+
+       platform_set_drvdata(pdev, priv);
+
+       dev_info(&pdev->dev, "Broadcom UniMAC MDIO bus at 0x%p\n", priv->base);
+
+       return 0;
+
+out_mdio_irq:
+       kfree(bus->irq);
+out_mdio_free:
+       mdiobus_free(bus);
+       return ret;
+}
+
+static int unimac_mdio_remove(struct platform_device *pdev)
+{
+       struct unimac_mdio_priv *priv = platform_get_drvdata(pdev);
+
+       mdiobus_unregister(priv->mii_bus);
+       kfree(priv->mii_bus->irq);
+       mdiobus_free(priv->mii_bus);
+
+       return 0;
+}
+
+static struct of_device_id unimac_mdio_ids[] = {
+       { .compatible = "brcm,genet-mdio-v4", },
+       { .compatible = "brcm,genet-mdio-v3", },
+       { .compatible = "brcm,genet-mdio-v2", },
+       { .compatible = "brcm,genet-mdio-v1", },
+       { .compatible = "brcm,unimac-mdio", },
+       { /* sentinel */ },
+};
+
+static struct platform_driver unimac_mdio_driver = {
+       .driver = {
+               .name = "unimac-mdio",
+               .owner = THIS_MODULE,
+               .of_match_table = unimac_mdio_ids,
+       },
+       .probe  = unimac_mdio_probe,
+       .remove = unimac_mdio_remove,
+};
+module_platform_driver(unimac_mdio_driver);
+
+MODULE_AUTHOR("Broadcom Corporation");
+MODULE_DESCRIPTION("Broadcom UniMAC MDIO bus controller");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:unimac-mdio");
index 4eaadcfcb0fe5ed2d5bd82a4632989916ade90e2..50051f271b10e8c02f34fae073f8d48ee15b8a97 100644 (file)
@@ -553,8 +553,14 @@ static ssize_t
 phy_interface_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct phy_device *phydev = to_phy_device(dev);
+       const char *mode = NULL;
 
-       return sprintf(buf, "%s\n", phy_modes(phydev->interface));
+       if (phy_is_internal(phydev))
+               mode = "internal";
+       else
+               mode = phy_modes(phydev->interface);
+
+       return sprintf(buf, "%s\n", mode);
 }
 static DEVICE_ATTR_RO(phy_interface);
 
index c94e2a27446a33a685b8b1c17dee4e559c33afd7..1dfffdc9dfc3577bd6893688da191c38539e243f 100644 (file)
@@ -955,7 +955,7 @@ static inline void mmd_phy_indirect(struct mii_bus *bus, int prtad, int devad,
  * 3) Write reg 13 // MMD Data Command for MMD DEVAD
  * 3) Read  reg 14 // Read MMD data
  */
-static int phy_read_mmd_indirect(struct phy_device *phydev, int prtad,
+int phy_read_mmd_indirect(struct phy_device *phydev, int prtad,
                                 int devad, int addr)
 {
        struct phy_driver *phydrv = phydev->drv;
@@ -971,6 +971,7 @@ static int phy_read_mmd_indirect(struct phy_device *phydev, int prtad,
        }
        return value;
 }
+EXPORT_SYMBOL(phy_read_mmd_indirect);
 
 /**
  * phy_write_mmd_indirect - writes data to the MMD registers
@@ -988,7 +989,7 @@ static int phy_read_mmd_indirect(struct phy_device *phydev, int prtad,
  * 3) Write reg 13 // MMD Data Command for MMD DEVAD
  * 3) Write reg 14 // Write MMD data
  */
-static void phy_write_mmd_indirect(struct phy_device *phydev, int prtad,
+void phy_write_mmd_indirect(struct phy_device *phydev, int prtad,
                                   int devad, int addr, u32 data)
 {
        struct phy_driver *phydrv = phydev->drv;
@@ -1002,6 +1003,7 @@ static void phy_write_mmd_indirect(struct phy_device *phydev, int prtad,
                phydrv->write_mmd_indirect(phydev, prtad, devad, addr, data);
        }
 }
+EXPORT_SYMBOL(phy_write_mmd_indirect);
 
 /**
  * phy_init_eee - init and check the EEE feature
@@ -1017,12 +1019,14 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable)
 {
        /* According to 802.3az,the EEE is supported only in full duplex-mode.
         * Also EEE feature is active when core is operating with MII, GMII
-        * or RGMII.
+        * or RGMII. Internal PHYs are also allowed to proceed and should
+        * return an error if they do not support EEE.
         */
        if ((phydev->duplex == DUPLEX_FULL) &&
            ((phydev->interface == PHY_INTERFACE_MODE_MII) ||
            (phydev->interface == PHY_INTERFACE_MODE_GMII) ||
-           (phydev->interface == PHY_INTERFACE_MODE_RGMII))) {
+           (phydev->interface == PHY_INTERFACE_MODE_RGMII) ||
+            phy_is_internal(phydev))) {
                int eee_lp, eee_cap, eee_adv;
                u32 lp, cap, adv;
                int status;
@@ -1036,31 +1040,31 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable)
                /* First check if the EEE ability is supported */
                eee_cap = phy_read_mmd_indirect(phydev, MDIO_PCS_EEE_ABLE,
                                                MDIO_MMD_PCS, phydev->addr);
-               if (eee_cap < 0)
-                       return eee_cap;
+               if (eee_cap <= 0)
+                       goto eee_exit_err;
 
                cap = mmd_eee_cap_to_ethtool_sup_t(eee_cap);
                if (!cap)
-                       return -EPROTONOSUPPORT;
+                       goto eee_exit_err;
 
                /* Check which link settings negotiated and verify it in
                 * the EEE advertising registers.
                 */
                eee_lp = phy_read_mmd_indirect(phydev, MDIO_AN_EEE_LPABLE,
                                               MDIO_MMD_AN, phydev->addr);
-               if (eee_lp < 0)
-                       return eee_lp;
+               if (eee_lp <= 0)
+                       goto eee_exit_err;
 
                eee_adv = phy_read_mmd_indirect(phydev, MDIO_AN_EEE_ADV,
                                                MDIO_MMD_AN, phydev->addr);
-               if (eee_adv < 0)
-                       return eee_adv;
+               if (eee_adv <= 0)
+                       goto eee_exit_err;
 
                adv = mmd_eee_adv_to_ethtool_adv_t(eee_adv);
                lp = mmd_eee_adv_to_ethtool_adv_t(eee_lp);
                idx = phy_find_setting(phydev->speed, phydev->duplex);
                if (!(lp & adv & settings[idx].setting))
-                       return -EPROTONOSUPPORT;
+                       goto eee_exit_err;
 
                if (clk_stop_enable) {
                        /* Configure the PHY to stop receiving xMII
@@ -1080,7 +1084,7 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable)
 
                return 0; /* EEE supported */
        }
-
+eee_exit_err:
        return -EPROTONOSUPPORT;
 }
 EXPORT_SYMBOL(phy_init_eee);
index ca5ec3e18d3662daeebd999291cc6a78c73e79de..3fc91e89f5a564bb36ab251c81ec083fc7cab68d 100644 (file)
@@ -230,13 +230,13 @@ static int get_phy_c45_ids(struct mii_bus *bus, int addr, u32 *phy_id,
        for (i = 1;
             i < num_ids && c45_ids->devices_in_package == 0;
             i++) {
-               reg_addr = MII_ADDR_C45 | i << 16 | 6;
+               reg_addr = MII_ADDR_C45 | i << 16 | MDIO_DEVS2;
                phy_reg = mdiobus_read(bus, addr, reg_addr);
                if (phy_reg < 0)
                        return -EIO;
                c45_ids->devices_in_package = (phy_reg & 0xffff) << 16;
 
-               reg_addr = MII_ADDR_C45 | i << 16 | 5;
+               reg_addr = MII_ADDR_C45 | i << 16 | MDIO_DEVS1;
                phy_reg = mdiobus_read(bus, addr, reg_addr);
                if (phy_reg < 0)
                        return -EIO;
index 180c49479c42f9b4a19f070056b782923de5084c..a4b08198fb9f28363ef1a49a5b84ec64edeabcf9 100644 (file)
@@ -42,6 +42,22 @@ static int smsc_phy_ack_interrupt(struct phy_device *phydev)
 }
 
 static int smsc_phy_config_init(struct phy_device *phydev)
+{
+       int rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
+
+       if (rc < 0)
+               return rc;
+
+       /* Enable energy detect mode for this SMSC Transceivers */
+       rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS,
+                      rc | MII_LAN83C185_EDPWRDOWN);
+       if (rc < 0)
+               return rc;
+
+       return smsc_phy_ack_interrupt(phydev);
+}
+
+static int smsc_phy_reset(struct phy_device *phydev)
 {
        int rc = phy_read(phydev, MII_LAN83C185_SPECIAL_MODES);
        if (rc < 0)
@@ -66,18 +82,7 @@ static int smsc_phy_config_init(struct phy_device *phydev)
                        rc = phy_read(phydev, MII_BMCR);
                } while (rc & BMCR_RESET);
        }
-
-       rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
-       if (rc < 0)
-               return rc;
-
-       /* Enable energy detect mode for this SMSC Transceivers */
-       rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS,
-                      rc | MII_LAN83C185_EDPWRDOWN);
-       if (rc < 0)
-               return rc;
-
-       return smsc_phy_ack_interrupt (phydev);
+       return 0;
 }
 
 static int lan911x_config_init(struct phy_device *phydev)
@@ -142,6 +147,7 @@ static struct phy_driver smsc_phy_driver[] = {
        .config_aneg    = genphy_config_aneg,
        .read_status    = genphy_read_status,
        .config_init    = smsc_phy_config_init,
+       .soft_reset     = smsc_phy_reset,
 
        /* IRQ related */
        .ack_interrupt  = smsc_phy_ack_interrupt,
@@ -164,6 +170,7 @@ static struct phy_driver smsc_phy_driver[] = {
        .config_aneg    = genphy_config_aneg,
        .read_status    = genphy_read_status,
        .config_init    = smsc_phy_config_init,
+       .soft_reset     = smsc_phy_reset,
 
        /* IRQ related */
        .ack_interrupt  = smsc_phy_ack_interrupt,
@@ -186,6 +193,7 @@ static struct phy_driver smsc_phy_driver[] = {
        .config_aneg    = genphy_config_aneg,
        .read_status    = genphy_read_status,
        .config_init    = smsc_phy_config_init,
+       .soft_reset     = smsc_phy_reset,
 
        /* IRQ related */
        .ack_interrupt  = smsc_phy_ack_interrupt,
@@ -230,6 +238,7 @@ static struct phy_driver smsc_phy_driver[] = {
        .config_aneg    = genphy_config_aneg,
        .read_status    = lan87xx_read_status,
        .config_init    = smsc_phy_config_init,
+       .soft_reset     = smsc_phy_reset,
 
        /* IRQ related */
        .ack_interrupt  = smsc_phy_ack_interrupt,
index ae7cd7f3656d04174b74ae534814029795217f18..92578d72e4ee51ce26d3e23d4b86099a0097801d 100644 (file)
@@ -47,22 +47,22 @@ static const int phy_BCM5400_link_table[8][3] = {
        { 1, 0, 1 },    /* 1000BT */
 };
 
-static inline int __phy_read(struct mii_phy* phy, int id, int reg)
+static inline int __sungem_phy_read(struct mii_phy* phy, int id, int reg)
 {
        return phy->mdio_read(phy->dev, id, reg);
 }
 
-static inline void __phy_write(struct mii_phy* phy, int id, int reg, int val)
+static inline void __sungem_phy_write(struct mii_phy* phy, int id, int reg, int val)
 {
        phy->mdio_write(phy->dev, id, reg, val);
 }
 
-static inline int phy_read(struct mii_phy* phy, int reg)
+static inline int sungem_phy_read(struct mii_phy* phy, int reg)
 {
        return phy->mdio_read(phy->dev, phy->mii_id, reg);
 }
 
-static inline void phy_write(struct mii_phy* phy, int reg, int val)
+static inline void sungem_phy_write(struct mii_phy* phy, int reg, int val)
 {
        phy->mdio_write(phy->dev, phy->mii_id, reg, val);
 }
@@ -72,21 +72,21 @@ static int reset_one_mii_phy(struct mii_phy* phy, int phy_id)
        u16 val;
        int limit = 10000;
 
-       val = __phy_read(phy, phy_id, MII_BMCR);
+       val = __sungem_phy_read(phy, phy_id, MII_BMCR);
        val &= ~(BMCR_ISOLATE | BMCR_PDOWN);
        val |= BMCR_RESET;
-       __phy_write(phy, phy_id, MII_BMCR, val);
+       __sungem_phy_write(phy, phy_id, MII_BMCR, val);
 
        udelay(100);
 
        while (--limit) {
-               val = __phy_read(phy, phy_id, MII_BMCR);
+               val = __sungem_phy_read(phy, phy_id, MII_BMCR);
                if ((val & BMCR_RESET) == 0)
                        break;
                udelay(10);
        }
        if ((val & BMCR_ISOLATE) && limit > 0)
-               __phy_write(phy, phy_id, MII_BMCR, val & ~BMCR_ISOLATE);
+               __sungem_phy_write(phy, phy_id, MII_BMCR, val & ~BMCR_ISOLATE);
 
        return limit <= 0;
 }
@@ -95,19 +95,19 @@ static int bcm5201_init(struct mii_phy* phy)
 {
        u16 data;
 
-       data = phy_read(phy, MII_BCM5201_MULTIPHY);
+       data = sungem_phy_read(phy, MII_BCM5201_MULTIPHY);
        data &= ~MII_BCM5201_MULTIPHY_SUPERISOLATE;
-       phy_write(phy, MII_BCM5201_MULTIPHY, data);
+       sungem_phy_write(phy, MII_BCM5201_MULTIPHY, data);
 
-       phy_write(phy, MII_BCM5201_INTERRUPT, 0);
+       sungem_phy_write(phy, MII_BCM5201_INTERRUPT, 0);
 
        return 0;
 }
 
 static int bcm5201_suspend(struct mii_phy* phy)
 {
-       phy_write(phy, MII_BCM5201_INTERRUPT, 0);
-       phy_write(phy, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE);
+       sungem_phy_write(phy, MII_BCM5201_INTERRUPT, 0);
+       sungem_phy_write(phy, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE);
 
        return 0;
 }
@@ -116,20 +116,20 @@ static int bcm5221_init(struct mii_phy* phy)
 {
        u16 data;
 
-       data = phy_read(phy, MII_BCM5221_TEST);
-       phy_write(phy, MII_BCM5221_TEST,
+       data = sungem_phy_read(phy, MII_BCM5221_TEST);
+       sungem_phy_write(phy, MII_BCM5221_TEST,
                data | MII_BCM5221_TEST_ENABLE_SHADOWS);
 
-       data = phy_read(phy, MII_BCM5221_SHDOW_AUX_STAT2);
-       phy_write(phy, MII_BCM5221_SHDOW_AUX_STAT2,
+       data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_STAT2);
+       sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_STAT2,
                data | MII_BCM5221_SHDOW_AUX_STAT2_APD);
 
-       data = phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
-       phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
+       data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
+       sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
                data | MII_BCM5221_SHDOW_AUX_MODE4_CLKLOPWR);
 
-       data = phy_read(phy, MII_BCM5221_TEST);
-       phy_write(phy, MII_BCM5221_TEST,
+       data = sungem_phy_read(phy, MII_BCM5221_TEST);
+       sungem_phy_write(phy, MII_BCM5221_TEST,
                data & ~MII_BCM5221_TEST_ENABLE_SHADOWS);
 
        return 0;
@@ -139,12 +139,12 @@ static int bcm5221_suspend(struct mii_phy* phy)
 {
        u16 data;
 
-       data = phy_read(phy, MII_BCM5221_TEST);
-       phy_write(phy, MII_BCM5221_TEST,
+       data = sungem_phy_read(phy, MII_BCM5221_TEST);
+       sungem_phy_write(phy, MII_BCM5221_TEST,
                data | MII_BCM5221_TEST_ENABLE_SHADOWS);
 
-       data = phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
-       phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
+       data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
+       sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
                  data | MII_BCM5221_SHDOW_AUX_MODE4_IDDQMODE);
 
        return 0;
@@ -154,20 +154,20 @@ static int bcm5241_init(struct mii_phy* phy)
 {
        u16 data;
 
-       data = phy_read(phy, MII_BCM5221_TEST);
-       phy_write(phy, MII_BCM5221_TEST,
+       data = sungem_phy_read(phy, MII_BCM5221_TEST);
+       sungem_phy_write(phy, MII_BCM5221_TEST,
                data | MII_BCM5221_TEST_ENABLE_SHADOWS);
 
-       data = phy_read(phy, MII_BCM5221_SHDOW_AUX_STAT2);
-       phy_write(phy, MII_BCM5221_SHDOW_AUX_STAT2,
+       data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_STAT2);
+       sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_STAT2,
                data | MII_BCM5221_SHDOW_AUX_STAT2_APD);
 
-       data = phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
-       phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
+       data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
+       sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
                data & ~MII_BCM5241_SHDOW_AUX_MODE4_STANDBYPWR);
 
-       data = phy_read(phy, MII_BCM5221_TEST);
-       phy_write(phy, MII_BCM5221_TEST,
+       data = sungem_phy_read(phy, MII_BCM5221_TEST);
+       sungem_phy_write(phy, MII_BCM5221_TEST,
                data & ~MII_BCM5221_TEST_ENABLE_SHADOWS);
 
        return 0;
@@ -177,12 +177,12 @@ static int bcm5241_suspend(struct mii_phy* phy)
 {
        u16 data;
 
-       data = phy_read(phy, MII_BCM5221_TEST);
-       phy_write(phy, MII_BCM5221_TEST,
+       data = sungem_phy_read(phy, MII_BCM5221_TEST);
+       sungem_phy_write(phy, MII_BCM5221_TEST,
                data | MII_BCM5221_TEST_ENABLE_SHADOWS);
 
-       data = phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
-       phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
+       data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
+       sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
                  data | MII_BCM5241_SHDOW_AUX_MODE4_STANDBYPWR);
 
        return 0;
@@ -193,26 +193,26 @@ static int bcm5400_init(struct mii_phy* phy)
        u16 data;
 
        /* Configure for gigabit full duplex */
-       data = phy_read(phy, MII_BCM5400_AUXCONTROL);
+       data = sungem_phy_read(phy, MII_BCM5400_AUXCONTROL);
        data |= MII_BCM5400_AUXCONTROL_PWR10BASET;
-       phy_write(phy, MII_BCM5400_AUXCONTROL, data);
+       sungem_phy_write(phy, MII_BCM5400_AUXCONTROL, data);
 
-       data = phy_read(phy, MII_BCM5400_GB_CONTROL);
+       data = sungem_phy_read(phy, MII_BCM5400_GB_CONTROL);
        data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
-       phy_write(phy, MII_BCM5400_GB_CONTROL, data);
+       sungem_phy_write(phy, MII_BCM5400_GB_CONTROL, data);
 
        udelay(100);
 
        /* Reset and configure cascaded 10/100 PHY */
        (void)reset_one_mii_phy(phy, 0x1f);
 
-       data = __phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
+       data = __sungem_phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
        data |= MII_BCM5201_MULTIPHY_SERIALMODE;
-       __phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
+       __sungem_phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
 
-       data = phy_read(phy, MII_BCM5400_AUXCONTROL);
+       data = sungem_phy_read(phy, MII_BCM5400_AUXCONTROL);
        data &= ~MII_BCM5400_AUXCONTROL_PWR10BASET;
-       phy_write(phy, MII_BCM5400_AUXCONTROL, data);
+       sungem_phy_write(phy, MII_BCM5400_AUXCONTROL, data);
 
        return 0;
 }
@@ -220,7 +220,7 @@ static int bcm5400_init(struct mii_phy* phy)
 static int bcm5400_suspend(struct mii_phy* phy)
 {
 #if 0 /* Commented out in Darwin... someone has those dawn docs ? */
-       phy_write(phy, MII_BMCR, BMCR_PDOWN);
+       sungem_phy_write(phy, MII_BMCR, BMCR_PDOWN);
 #endif
        return 0;
 }
@@ -230,7 +230,7 @@ static int bcm5401_init(struct mii_phy* phy)
        u16 data;
        int rev;
 
-       rev = phy_read(phy, MII_PHYSID2) & 0x000f;
+       rev = sungem_phy_read(phy, MII_PHYSID2) & 0x000f;
        if (rev == 0 || rev == 3) {
                /* Some revisions of 5401 appear to need this
                 * initialisation sequence to disable, according
@@ -243,32 +243,32 @@ static int bcm5401_init(struct mii_phy* phy)
                 * Note: This should (and does) match tg3_init_5401phy_dsp
                 *       in the tg3.c driver. -DaveM
                 */
-               phy_write(phy, 0x18, 0x0c20);
-               phy_write(phy, 0x17, 0x0012);
-               phy_write(phy, 0x15, 0x1804);
-               phy_write(phy, 0x17, 0x0013);
-               phy_write(phy, 0x15, 0x1204);
-               phy_write(phy, 0x17, 0x8006);
-               phy_write(phy, 0x15, 0x0132);
-               phy_write(phy, 0x17, 0x8006);
-               phy_write(phy, 0x15, 0x0232);
-               phy_write(phy, 0x17, 0x201f);
-               phy_write(phy, 0x15, 0x0a20);
+               sungem_phy_write(phy, 0x18, 0x0c20);
+               sungem_phy_write(phy, 0x17, 0x0012);
+               sungem_phy_write(phy, 0x15, 0x1804);
+               sungem_phy_write(phy, 0x17, 0x0013);
+               sungem_phy_write(phy, 0x15, 0x1204);
+               sungem_phy_write(phy, 0x17, 0x8006);
+               sungem_phy_write(phy, 0x15, 0x0132);
+               sungem_phy_write(phy, 0x17, 0x8006);
+               sungem_phy_write(phy, 0x15, 0x0232);
+               sungem_phy_write(phy, 0x17, 0x201f);
+               sungem_phy_write(phy, 0x15, 0x0a20);
        }
 
        /* Configure for gigabit full duplex */
-       data = phy_read(phy, MII_BCM5400_GB_CONTROL);
+       data = sungem_phy_read(phy, MII_BCM5400_GB_CONTROL);
        data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
-       phy_write(phy, MII_BCM5400_GB_CONTROL, data);
+       sungem_phy_write(phy, MII_BCM5400_GB_CONTROL, data);
 
        udelay(10);
 
        /* Reset and configure cascaded 10/100 PHY */
        (void)reset_one_mii_phy(phy, 0x1f);
 
-       data = __phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
+       data = __sungem_phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
        data |= MII_BCM5201_MULTIPHY_SERIALMODE;
-       __phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
+       __sungem_phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
 
        return 0;
 }
@@ -276,7 +276,7 @@ static int bcm5401_init(struct mii_phy* phy)
 static int bcm5401_suspend(struct mii_phy* phy)
 {
 #if 0 /* Commented out in Darwin... someone has those dawn docs ? */
-       phy_write(phy, MII_BMCR, BMCR_PDOWN);
+       sungem_phy_write(phy, MII_BMCR, BMCR_PDOWN);
 #endif
        return 0;
 }
@@ -288,19 +288,19 @@ static int bcm5411_init(struct mii_phy* phy)
        /* Here's some more Apple black magic to setup
         * some voltage stuffs.
         */
-       phy_write(phy, 0x1c, 0x8c23);
-       phy_write(phy, 0x1c, 0x8ca3);
-       phy_write(phy, 0x1c, 0x8c23);
+       sungem_phy_write(phy, 0x1c, 0x8c23);
+       sungem_phy_write(phy, 0x1c, 0x8ca3);
+       sungem_phy_write(phy, 0x1c, 0x8c23);
 
        /* Here, Apple seems to want to reset it, do
         * it as well
         */
-       phy_write(phy, MII_BMCR, BMCR_RESET);
-       phy_write(phy, MII_BMCR, 0x1340);
+       sungem_phy_write(phy, MII_BMCR, BMCR_RESET);
+       sungem_phy_write(phy, MII_BMCR, 0x1340);
 
-       data = phy_read(phy, MII_BCM5400_GB_CONTROL);
+       data = sungem_phy_read(phy, MII_BCM5400_GB_CONTROL);
        data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
-       phy_write(phy, MII_BCM5400_GB_CONTROL, data);
+       sungem_phy_write(phy, MII_BCM5400_GB_CONTROL, data);
 
        udelay(10);
 
@@ -321,7 +321,7 @@ static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
        phy->advertising = advertise;
 
        /* Setup standard advertise */
-       adv = phy_read(phy, MII_ADVERTISE);
+       adv = sungem_phy_read(phy, MII_ADVERTISE);
        adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
        if (advertise & ADVERTISED_10baseT_Half)
                adv |= ADVERTISE_10HALF;
@@ -331,12 +331,12 @@ static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
                adv |= ADVERTISE_100HALF;
        if (advertise & ADVERTISED_100baseT_Full)
                adv |= ADVERTISE_100FULL;
-       phy_write(phy, MII_ADVERTISE, adv);
+       sungem_phy_write(phy, MII_ADVERTISE, adv);
 
        /* Start/Restart aneg */
-       ctl = phy_read(phy, MII_BMCR);
+       ctl = sungem_phy_read(phy, MII_BMCR);
        ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
-       phy_write(phy, MII_BMCR, ctl);
+       sungem_phy_write(phy, MII_BMCR, ctl);
 
        return 0;
 }
@@ -350,11 +350,11 @@ static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
        phy->duplex = fd;
        phy->pause = 0;
 
-       ctl = phy_read(phy, MII_BMCR);
+       ctl = sungem_phy_read(phy, MII_BMCR);
        ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_ANENABLE);
 
        /* First reset the PHY */
-       phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
+       sungem_phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
 
        /* Select speed & duplex */
        switch(speed) {
@@ -369,7 +369,7 @@ static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
        }
        if (fd == DUPLEX_FULL)
                ctl |= BMCR_FULLDPLX;
-       phy_write(phy, MII_BMCR, ctl);
+       sungem_phy_write(phy, MII_BMCR, ctl);
 
        return 0;
 }
@@ -378,8 +378,8 @@ static int genmii_poll_link(struct mii_phy *phy)
 {
        u16 status;
 
-       (void)phy_read(phy, MII_BMSR);
-       status = phy_read(phy, MII_BMSR);
+       (void)sungem_phy_read(phy, MII_BMSR);
+       status = sungem_phy_read(phy, MII_BMSR);
        if ((status & BMSR_LSTATUS) == 0)
                return 0;
        if (phy->autoneg && !(status & BMSR_ANEGCOMPLETE))
@@ -392,7 +392,7 @@ static int genmii_read_link(struct mii_phy *phy)
        u16 lpa;
 
        if (phy->autoneg) {
-               lpa = phy_read(phy, MII_LPA);
+               lpa = sungem_phy_read(phy, MII_LPA);
 
                if (lpa & (LPA_10FULL | LPA_100FULL))
                        phy->duplex = DUPLEX_FULL;
@@ -413,7 +413,7 @@ static int genmii_read_link(struct mii_phy *phy)
 
 static int generic_suspend(struct mii_phy* phy)
 {
-       phy_write(phy, MII_BMCR, BMCR_PDOWN);
+       sungem_phy_write(phy, MII_BMCR, BMCR_PDOWN);
 
        return 0;
 }
@@ -423,27 +423,27 @@ static int bcm5421_init(struct mii_phy* phy)
        u16 data;
        unsigned int id;
 
-       id = (phy_read(phy, MII_PHYSID1) << 16 | phy_read(phy, MII_PHYSID2));
+       id = (sungem_phy_read(phy, MII_PHYSID1) << 16 | sungem_phy_read(phy, MII_PHYSID2));
 
        /* Revision 0 of 5421 needs some fixups */
        if (id == 0x002060e0) {
                /* This is borrowed from MacOS
                 */
-               phy_write(phy, 0x18, 0x1007);
-               data = phy_read(phy, 0x18);
-               phy_write(phy, 0x18, data | 0x0400);
-               phy_write(phy, 0x18, 0x0007);
-               data = phy_read(phy, 0x18);
-               phy_write(phy, 0x18, data | 0x0800);
-               phy_write(phy, 0x17, 0x000a);
-               data = phy_read(phy, 0x15);
-               phy_write(phy, 0x15, data | 0x0200);
+               sungem_phy_write(phy, 0x18, 0x1007);
+               data = sungem_phy_read(phy, 0x18);
+               sungem_phy_write(phy, 0x18, data | 0x0400);
+               sungem_phy_write(phy, 0x18, 0x0007);
+               data = sungem_phy_read(phy, 0x18);
+               sungem_phy_write(phy, 0x18, data | 0x0800);
+               sungem_phy_write(phy, 0x17, 0x000a);
+               data = sungem_phy_read(phy, 0x15);
+               sungem_phy_write(phy, 0x15, data | 0x0200);
        }
 
        /* Pick up some init code from OF for K2 version */
        if ((id & 0xfffffff0) == 0x002062e0) {
-               phy_write(phy, 4, 0x01e1);
-               phy_write(phy, 9, 0x0300);
+               sungem_phy_write(phy, 4, 0x01e1);
+               sungem_phy_write(phy, 9, 0x0300);
        }
 
        /* Check if we can enable automatic low power */
@@ -455,9 +455,9 @@ static int bcm5421_init(struct mii_phy* phy)
                        can_low_power = 0;
                if (can_low_power) {
                        /* Enable automatic low-power */
-                       phy_write(phy, 0x1c, 0x9002);
-                       phy_write(phy, 0x1c, 0xa821);
-                       phy_write(phy, 0x1c, 0x941d);
+                       sungem_phy_write(phy, 0x1c, 0x9002);
+                       sungem_phy_write(phy, 0x1c, 0xa821);
+                       sungem_phy_write(phy, 0x1c, 0x941d);
                }
        }
 #endif /* CONFIG_PPC_PMAC */
@@ -476,7 +476,7 @@ static int bcm54xx_setup_aneg(struct mii_phy *phy, u32 advertise)
        phy->advertising = advertise;
 
        /* Setup standard advertise */
-       adv = phy_read(phy, MII_ADVERTISE);
+       adv = sungem_phy_read(phy, MII_ADVERTISE);
        adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
        if (advertise & ADVERTISED_10baseT_Half)
                adv |= ADVERTISE_10HALF;
@@ -490,21 +490,21 @@ static int bcm54xx_setup_aneg(struct mii_phy *phy, u32 advertise)
                adv |= ADVERTISE_PAUSE_CAP;
        if (advertise & ADVERTISED_Asym_Pause)
                adv |= ADVERTISE_PAUSE_ASYM;
-       phy_write(phy, MII_ADVERTISE, adv);
+       sungem_phy_write(phy, MII_ADVERTISE, adv);
 
        /* Setup 1000BT advertise */
-       adv = phy_read(phy, MII_1000BASETCONTROL);
+       adv = sungem_phy_read(phy, MII_1000BASETCONTROL);
        adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP|MII_1000BASETCONTROL_HALFDUPLEXCAP);
        if (advertise & SUPPORTED_1000baseT_Half)
                adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
        if (advertise & SUPPORTED_1000baseT_Full)
                adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
-       phy_write(phy, MII_1000BASETCONTROL, adv);
+       sungem_phy_write(phy, MII_1000BASETCONTROL, adv);
 
        /* Start/Restart aneg */
-       ctl = phy_read(phy, MII_BMCR);
+       ctl = sungem_phy_read(phy, MII_BMCR);
        ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
-       phy_write(phy, MII_BMCR, ctl);
+       sungem_phy_write(phy, MII_BMCR, ctl);
 
        return 0;
 }
@@ -518,11 +518,11 @@ static int bcm54xx_setup_forced(struct mii_phy *phy, int speed, int fd)
        phy->duplex = fd;
        phy->pause = 0;
 
-       ctl = phy_read(phy, MII_BMCR);
+       ctl = sungem_phy_read(phy, MII_BMCR);
        ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
 
        /* First reset the PHY */
-       phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
+       sungem_phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
 
        /* Select speed & duplex */
        switch(speed) {
@@ -539,7 +539,7 @@ static int bcm54xx_setup_forced(struct mii_phy *phy, int speed, int fd)
 
        // XXX Should we set the sungem to GII now on 1000BT ?
 
-       phy_write(phy, MII_BMCR, ctl);
+       sungem_phy_write(phy, MII_BMCR, ctl);
 
        return 0;
 }
@@ -550,7 +550,7 @@ static int bcm54xx_read_link(struct mii_phy *phy)
        u16 val;
 
        if (phy->autoneg) {
-               val = phy_read(phy, MII_BCM5400_AUXSTATUS);
+               val = sungem_phy_read(phy, MII_BCM5400_AUXSTATUS);
                link_mode = ((val & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >>
                             MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT);
                phy->duplex = phy_BCM5400_link_table[link_mode][0] ?
@@ -559,7 +559,7 @@ static int bcm54xx_read_link(struct mii_phy *phy)
                                SPEED_1000 :
                                (phy_BCM5400_link_table[link_mode][1] ?
                                 SPEED_100 : SPEED_10);
-               val = phy_read(phy, MII_LPA);
+               val = sungem_phy_read(phy, MII_LPA);
                phy->pause = (phy->duplex == DUPLEX_FULL) &&
                        ((val & LPA_PAUSE) != 0);
        }
@@ -575,19 +575,19 @@ static int marvell88e1111_init(struct mii_phy* phy)
        u16 rev;
 
        /* magic init sequence for rev 0 */
-       rev = phy_read(phy, MII_PHYSID2) & 0x000f;
+       rev = sungem_phy_read(phy, MII_PHYSID2) & 0x000f;
        if (rev == 0) {
-               phy_write(phy, 0x1d, 0x000a);
-               phy_write(phy, 0x1e, 0x0821);
+               sungem_phy_write(phy, 0x1d, 0x000a);
+               sungem_phy_write(phy, 0x1e, 0x0821);
 
-               phy_write(phy, 0x1d, 0x0006);
-               phy_write(phy, 0x1e, 0x8600);
+               sungem_phy_write(phy, 0x1d, 0x0006);
+               sungem_phy_write(phy, 0x1e, 0x8600);
 
-               phy_write(phy, 0x1d, 0x000b);
-               phy_write(phy, 0x1e, 0x0100);
+               sungem_phy_write(phy, 0x1d, 0x000b);
+               sungem_phy_write(phy, 0x1e, 0x0100);
 
-               phy_write(phy, 0x1d, 0x0004);
-               phy_write(phy, 0x1e, 0x4850);
+               sungem_phy_write(phy, 0x1d, 0x0004);
+               sungem_phy_write(phy, 0x1e, 0x4850);
        }
        return 0;
 }
@@ -600,8 +600,8 @@ static int bcm5421_poll_link(struct mii_phy* phy)
        int mode;
 
        /* find out in what mode we are */
-       phy_write(phy, MII_NCONFIG, 0x1000);
-       phy_reg = phy_read(phy, MII_NCONFIG);
+       sungem_phy_write(phy, MII_NCONFIG, 0x1000);
+       phy_reg = sungem_phy_read(phy, MII_NCONFIG);
 
        mode = (phy_reg & BCM5421_MODE_MASK) >> 5;
 
@@ -609,8 +609,8 @@ static int bcm5421_poll_link(struct mii_phy* phy)
                return genmii_poll_link(phy);
 
        /* try to find out whether we have a link */
-       phy_write(phy, MII_NCONFIG, 0x2000);
-       phy_reg = phy_read(phy, MII_NCONFIG);
+       sungem_phy_write(phy, MII_NCONFIG, 0x2000);
+       phy_reg = sungem_phy_read(phy, MII_NCONFIG);
 
        if (phy_reg & 0x0020)
                return 0;
@@ -624,8 +624,8 @@ static int bcm5421_read_link(struct mii_phy* phy)
        int mode;
 
        /* find out in what mode we are */
-       phy_write(phy, MII_NCONFIG, 0x1000);
-       phy_reg = phy_read(phy, MII_NCONFIG);
+       sungem_phy_write(phy, MII_NCONFIG, 0x1000);
+       phy_reg = sungem_phy_read(phy, MII_NCONFIG);
 
        mode = (phy_reg & BCM5421_MODE_MASK ) >> 5;
 
@@ -635,8 +635,8 @@ static int bcm5421_read_link(struct mii_phy* phy)
        phy->speed = SPEED_1000;
 
        /* find out whether we are running half- or full duplex */
-       phy_write(phy, MII_NCONFIG, 0x2000);
-       phy_reg = phy_read(phy, MII_NCONFIG);
+       sungem_phy_write(phy, MII_NCONFIG, 0x2000);
+       phy_reg = sungem_phy_read(phy, MII_NCONFIG);
 
        if ( (phy_reg & 0x0080) >> 7)
                phy->duplex |=  DUPLEX_HALF;
@@ -649,14 +649,14 @@ static int bcm5421_read_link(struct mii_phy* phy)
 static int bcm5421_enable_fiber(struct mii_phy* phy, int autoneg)
 {
        /* enable fiber mode */
-       phy_write(phy, MII_NCONFIG, 0x9020);
+       sungem_phy_write(phy, MII_NCONFIG, 0x9020);
        /* LEDs active in both modes, autosense prio = fiber */
-       phy_write(phy, MII_NCONFIG, 0x945f);
+       sungem_phy_write(phy, MII_NCONFIG, 0x945f);
 
        if (!autoneg) {
                /* switch off fibre autoneg */
-               phy_write(phy, MII_NCONFIG, 0xfc01);
-               phy_write(phy, 0x0b, 0x0004);
+               sungem_phy_write(phy, MII_NCONFIG, 0xfc01);
+               sungem_phy_write(phy, 0x0b, 0x0004);
        }
 
        phy->autoneg = autoneg;
@@ -673,8 +673,8 @@ static int bcm5461_poll_link(struct mii_phy* phy)
        int mode;
 
        /* find out in what mode we are */
-       phy_write(phy, MII_NCONFIG, 0x7c00);
-       phy_reg = phy_read(phy, MII_NCONFIG);
+       sungem_phy_write(phy, MII_NCONFIG, 0x7c00);
+       phy_reg = sungem_phy_read(phy, MII_NCONFIG);
 
        mode = (phy_reg & BCM5461_MODE_MASK ) >> 1;
 
@@ -682,8 +682,8 @@ static int bcm5461_poll_link(struct mii_phy* phy)
                return genmii_poll_link(phy);
 
        /* find out whether we have a link */
-       phy_write(phy, MII_NCONFIG, 0x7000);
-       phy_reg = phy_read(phy, MII_NCONFIG);
+       sungem_phy_write(phy, MII_NCONFIG, 0x7000);
+       phy_reg = sungem_phy_read(phy, MII_NCONFIG);
 
        if (phy_reg & BCM5461_FIBER_LINK)
                return 1;
@@ -699,8 +699,8 @@ static int bcm5461_read_link(struct mii_phy* phy)
        int mode;
 
        /* find out in what mode we are */
-       phy_write(phy, MII_NCONFIG, 0x7c00);
-       phy_reg = phy_read(phy, MII_NCONFIG);
+       sungem_phy_write(phy, MII_NCONFIG, 0x7c00);
+       phy_reg = sungem_phy_read(phy, MII_NCONFIG);
 
        mode = (phy_reg & BCM5461_MODE_MASK ) >> 1;
 
@@ -711,8 +711,8 @@ static int bcm5461_read_link(struct mii_phy* phy)
        phy->speed = SPEED_1000;
 
        /* find out whether we are running half- or full duplex */
-       phy_write(phy, MII_NCONFIG, 0x7000);
-       phy_reg = phy_read(phy, MII_NCONFIG);
+       sungem_phy_write(phy, MII_NCONFIG, 0x7000);
+       phy_reg = sungem_phy_read(phy, MII_NCONFIG);
 
        if (phy_reg & BCM5461_FIBER_DUPLEX)
                phy->duplex |=  DUPLEX_FULL;
@@ -725,15 +725,15 @@ static int bcm5461_read_link(struct mii_phy* phy)
 static int bcm5461_enable_fiber(struct mii_phy* phy, int autoneg)
 {
        /* select fiber mode, enable 1000 base-X registers */
-       phy_write(phy, MII_NCONFIG, 0xfc0b);
+       sungem_phy_write(phy, MII_NCONFIG, 0xfc0b);
 
        if (autoneg) {
                /* enable fiber with no autonegotiation */
-               phy_write(phy, MII_ADVERTISE, 0x01e0);
-               phy_write(phy, MII_BMCR, 0x1140);
+               sungem_phy_write(phy, MII_ADVERTISE, 0x01e0);
+               sungem_phy_write(phy, MII_BMCR, 0x1140);
        } else {
                /* enable fiber with autonegotiation */
-               phy_write(phy, MII_BMCR, 0x0140);
+               sungem_phy_write(phy, MII_BMCR, 0x0140);
        }
 
        phy->autoneg = autoneg;
@@ -752,7 +752,7 @@ static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise)
        phy->advertising = advertise;
 
        /* Setup standard advertise */
-       adv = phy_read(phy, MII_ADVERTISE);
+       adv = sungem_phy_read(phy, MII_ADVERTISE);
        adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
        if (advertise & ADVERTISED_10baseT_Half)
                adv |= ADVERTISE_10HALF;
@@ -766,7 +766,7 @@ static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise)
                adv |= ADVERTISE_PAUSE_CAP;
        if (advertise & ADVERTISED_Asym_Pause)
                adv |= ADVERTISE_PAUSE_ASYM;
-       phy_write(phy, MII_ADVERTISE, adv);
+       sungem_phy_write(phy, MII_ADVERTISE, adv);
 
        /* Setup 1000BT advertise & enable crossover detect
         * XXX How do we advertise 1000BT ? Darwin source is
@@ -774,7 +774,7 @@ static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise)
         * write to control... Someone has specs for those
         * beasts ?
         */
-       adv = phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);
+       adv = sungem_phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);
        adv |= MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX;
        adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP |
                        MII_1000BASETCONTROL_HALFDUPLEXCAP);
@@ -782,12 +782,12 @@ static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise)
                adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
        if (advertise & SUPPORTED_1000baseT_Full)
                adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
-       phy_write(phy, MII_1000BASETCONTROL, adv);
+       sungem_phy_write(phy, MII_1000BASETCONTROL, adv);
 
        /* Start/Restart aneg */
-       ctl = phy_read(phy, MII_BMCR);
+       ctl = sungem_phy_read(phy, MII_BMCR);
        ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
-       phy_write(phy, MII_BMCR, ctl);
+       sungem_phy_write(phy, MII_BMCR, ctl);
 
        return 0;
 }
@@ -801,7 +801,7 @@ static int marvell_setup_forced(struct mii_phy *phy, int speed, int fd)
        phy->duplex = fd;
        phy->pause = 0;
 
-       ctl = phy_read(phy, MII_BMCR);
+       ctl = sungem_phy_read(phy, MII_BMCR);
        ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
        ctl |= BMCR_RESET;
 
@@ -824,7 +824,7 @@ static int marvell_setup_forced(struct mii_phy *phy, int speed, int fd)
        /* Disable crossover. Again, the way Apple does it is strange,
         * though I don't assume they are wrong ;)
         */
-       ctl2 = phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);
+       ctl2 = sungem_phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);
        ctl2 &= ~(MII_M1011_PHY_SPEC_CONTROL_MANUAL_MDIX |
                MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX |
                MII_1000BASETCONTROL_FULLDUPLEXCAP |
@@ -833,11 +833,11 @@ static int marvell_setup_forced(struct mii_phy *phy, int speed, int fd)
                ctl2 |= (fd == DUPLEX_FULL) ?
                        MII_1000BASETCONTROL_FULLDUPLEXCAP :
                        MII_1000BASETCONTROL_HALFDUPLEXCAP;
-       phy_write(phy, MII_1000BASETCONTROL, ctl2);
+       sungem_phy_write(phy, MII_1000BASETCONTROL, ctl2);
 
        // XXX Should we set the sungem to GII now on 1000BT ?
 
-       phy_write(phy, MII_BMCR, ctl);
+       sungem_phy_write(phy, MII_BMCR, ctl);
 
        return 0;
 }
@@ -847,7 +847,7 @@ static int marvell_read_link(struct mii_phy *phy)
        u16 status, pmask;
 
        if (phy->autoneg) {
-               status = phy_read(phy, MII_M1011_PHY_SPEC_STATUS);
+               status = sungem_phy_read(phy, MII_M1011_PHY_SPEC_STATUS);
                if ((status & MII_M1011_PHY_SPEC_STATUS_RESOLVED) == 0)
                        return -EAGAIN;
                if (status & MII_M1011_PHY_SPEC_STATUS_1000)
@@ -1174,7 +1174,7 @@ int sungem_phy_probe(struct mii_phy *phy, int mii_id)
                goto fail;
 
        /* Read ID and find matching entry */
-       id = (phy_read(phy, MII_PHYSID1) << 16 | phy_read(phy, MII_PHYSID2));
+       id = (sungem_phy_read(phy, MII_PHYSID1) << 16 | sungem_phy_read(phy, MII_PHYSID2));
        printk(KERN_DEBUG KBUILD_MODNAME ": " "PHY ID: %x, addr: %x\n",
               id, mii_id);
        for (i=0; (def = mii_phy_table[i]) != NULL; i++)
index ef10302ec936ee5969001bb9da484b80d573c1ee..2277c3679a518e5b68ded6ff7e9bbe9404f71a1e 100644 (file)
@@ -1003,7 +1003,6 @@ static int team_port_enter(struct team *team, struct team_port *port)
        int err = 0;
 
        dev_hold(team->dev);
-       port->dev->priv_flags |= IFF_TEAM_PORT;
        if (team->ops.port_enter) {
                err = team->ops.port_enter(team, port);
                if (err) {
@@ -1016,7 +1015,6 @@ static int team_port_enter(struct team *team, struct team_port *port)
        return 0;
 
 err_port_enter:
-       port->dev->priv_flags &= ~IFF_TEAM_PORT;
        dev_put(team->dev);
 
        return err;
@@ -1026,7 +1024,6 @@ static void team_port_leave(struct team *team, struct team_port *port)
 {
        if (team->ops.port_leave)
                team->ops.port_leave(team, port);
-       port->dev->priv_flags &= ~IFF_TEAM_PORT;
        dev_put(team->dev);
 }
 
@@ -1075,6 +1072,25 @@ static void team_port_disable_netpoll(struct team_port *port)
 }
 #endif
 
+static int team_upper_dev_link(struct net_device *dev,
+                              struct net_device *port_dev)
+{
+       int err;
+
+       err = netdev_master_upper_dev_link(port_dev, dev);
+       if (err)
+               return err;
+       port_dev->priv_flags |= IFF_TEAM_PORT;
+       return 0;
+}
+
+static void team_upper_dev_unlink(struct net_device *dev,
+                                 struct net_device *port_dev)
+{
+       netdev_upper_dev_unlink(port_dev, dev);
+       port_dev->priv_flags &= ~IFF_TEAM_PORT;
+}
+
 static void __team_port_change_port_added(struct team_port *port, bool linkup);
 static int team_dev_type_check_change(struct net_device *dev,
                                      struct net_device *port_dev);
@@ -1161,13 +1177,6 @@ static int team_port_add(struct team *team, struct net_device *port_dev)
                goto err_enable_netpoll;
        }
 
-       err = netdev_master_upper_dev_link(port_dev, dev);
-       if (err) {
-               netdev_err(dev, "Device %s failed to set upper link\n",
-                          portname);
-               goto err_set_upper_link;
-       }
-
        err = netdev_rx_handler_register(port_dev, team_handle_frame,
                                         port);
        if (err) {
@@ -1176,6 +1185,13 @@ static int team_port_add(struct team *team, struct net_device *port_dev)
                goto err_handler_register;
        }
 
+       err = team_upper_dev_link(dev, port_dev);
+       if (err) {
+               netdev_err(dev, "Device %s failed to set upper link\n",
+                          portname);
+               goto err_set_upper_link;
+       }
+
        err = __team_option_inst_add_port(team, port);
        if (err) {
                netdev_err(dev, "Device %s failed to add per-port options\n",
@@ -1195,12 +1211,12 @@ static int team_port_add(struct team *team, struct net_device *port_dev)
        return 0;
 
 err_option_port_add:
+       team_upper_dev_unlink(dev, port_dev);
+
+err_set_upper_link:
        netdev_rx_handler_unregister(port_dev);
 
 err_handler_register:
-       netdev_upper_dev_unlink(port_dev, dev);
-
-err_set_upper_link:
        team_port_disable_netpoll(port);
 
 err_enable_netpoll:
@@ -1239,8 +1255,8 @@ static int team_port_del(struct team *team, struct net_device *port_dev)
 
        team_port_disable(team, port);
        list_del_rcu(&port->list);
+       team_upper_dev_unlink(dev, port_dev);
        netdev_rx_handler_unregister(port_dev);
-       netdev_upper_dev_unlink(port_dev, dev);
        team_port_disable_netpoll(port);
        vlan_vids_del_by_dev(port_dev, dev);
        dev_uc_unsync(port_dev, dev);
index 87f710476217d8a02cc496925d57ac5fcd0021c8..2130c757b37e7ddc197c1fc34d2639374ad69292 100644 (file)
@@ -424,7 +424,7 @@ enum rtl_register_content {
        FULL_DUP        = 0x01,
 };
 
-#define RTL8152_MAX_TX         10
+#define RTL8152_MAX_TX         4
 #define RTL8152_MAX_RX         10
 #define INTBUFSIZE             2
 #define CRC_SIZE               4
@@ -607,9 +607,9 @@ enum tx_csum_stat {
  * 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;
+static unsigned int agg_buf_sz = 16384;
 
-#define RTL_LIMITED_TSO_SIZE   (rx_buf_sz - sizeof(struct tx_desc) - \
+#define RTL_LIMITED_TSO_SIZE   (agg_buf_sz - sizeof(struct tx_desc) - \
                                 VLAN_ETH_HLEN - VLAN_HLEN)
 
 static
@@ -623,8 +623,8 @@ int get_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
                return -ENOMEM;
 
        ret = usb_control_msg(tp->udev, usb_rcvctrlpipe(tp->udev, 0),
-                              RTL8152_REQ_GET_REGS, RTL8152_REQT_READ,
-                              value, index, tmp, size, 500);
+                             RTL8152_REQ_GET_REGS, RTL8152_REQT_READ,
+                             value, index, tmp, size, 500);
 
        memcpy(data, tmp, size);
        kfree(tmp);
@@ -643,8 +643,8 @@ int set_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
                return -ENOMEM;
 
        ret = usb_control_msg(tp->udev, usb_sndctrlpipe(tp->udev, 0),
-                              RTL8152_REQ_SET_REGS, RTL8152_REQT_WRITE,
-                              value, index, tmp, size, 500);
+                             RTL8152_REQ_SET_REGS, RTL8152_REQT_WRITE,
+                             value, index, tmp, size, 500);
 
        kfree(tmp);
 
@@ -652,7 +652,7 @@ int set_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
 }
 
 static int generic_ocp_read(struct r8152 *tp, u16 index, u16 size,
-                               void *data, u16 type)
+                           void *data, u16 type)
 {
        u16 limit = 64;
        int ret = 0;
@@ -692,7 +692,7 @@ static int generic_ocp_read(struct r8152 *tp, u16 index, u16 size,
 }
 
 static int generic_ocp_write(struct r8152 *tp, u16 index, u16 byteen,
-                               u16 size, void *data, u16 type)
+                            u16 size, void *data, u16 type)
 {
        int ret;
        u16 byteen_start, byteen_end, byen;
@@ -726,8 +726,8 @@ static int generic_ocp_write(struct r8152 *tp, u16 index, u16 byteen,
                while (size) {
                        if (size > limit) {
                                ret = set_registers(tp, index,
-                                       type | BYTE_EN_DWORD,
-                                       limit, data);
+                                                   type | BYTE_EN_DWORD,
+                                                   limit, data);
                                if (ret < 0)
                                        goto error1;
 
@@ -736,8 +736,8 @@ static int generic_ocp_write(struct r8152 *tp, u16 index, u16 byteen,
                                size -= limit;
                        } else {
                                ret = set_registers(tp, index,
-                                       type | BYTE_EN_DWORD,
-                                       size, data);
+                                                   type | BYTE_EN_DWORD,
+                                                   size, data);
                                if (ret < 0)
                                        goto error1;
 
@@ -972,36 +972,8 @@ void write_mii_word(struct net_device *netdev, int phy_id, int reg, int val)
        usb_autopm_put_interface(tp->intf);
 }
 
-static
-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 (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 {
-               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);
-       }
-}
+static int
+r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags);
 
 static int rtl8152_set_mac_address(struct net_device *netdev, void *p)
 {
@@ -1020,6 +992,37 @@ static int rtl8152_set_mac_address(struct net_device *netdev, void *p)
        return 0;
 }
 
+static int set_ethernet_addr(struct r8152 *tp)
+{
+       struct net_device *dev = tp->netdev;
+       struct sockaddr sa;
+       int ret;
+
+       if (tp->version == RTL_VER_01)
+               ret = pla_ocp_read(tp, PLA_IDR, 8, sa.sa_data);
+       else
+               ret = pla_ocp_read(tp, PLA_BACKUP, 8, sa.sa_data);
+
+       if (ret < 0) {
+               netif_err(tp, probe, dev, "Get ether addr fail\n");
+       } else if (!is_valid_ether_addr(sa.sa_data)) {
+               netif_err(tp, probe, dev, "Invalid ether addr %pM\n",
+                         sa.sa_data);
+               eth_hw_addr_random(dev);
+               ether_addr_copy(sa.sa_data, dev->dev_addr);
+               ret = rtl8152_set_mac_address(dev, &sa);
+               netif_info(tp, probe, dev, "Random ether addr %pM\n",
+                          sa.sa_data);
+       } else {
+               if (tp->version == RTL_VER_01)
+                       ether_addr_copy(dev->dev_addr, sa.sa_data);
+               else
+                       ret = rtl8152_set_mac_address(dev, &sa);
+       }
+
+       return ret;
+}
+
 static void read_bulk_callback(struct urb *urb)
 {
        struct net_device *netdev;
@@ -1248,13 +1251,13 @@ static int alloc_all_mem(struct r8152 *tp)
        skb_queue_head_init(&tp->tx_queue);
 
        for (i = 0; i < RTL8152_MAX_RX; i++) {
-               buf = kmalloc_node(rx_buf_sz, GFP_KERNEL, node);
+               buf = kmalloc_node(agg_buf_sz, GFP_KERNEL, node);
                if (!buf)
                        goto err1;
 
                if (buf != rx_agg_align(buf)) {
                        kfree(buf);
-                       buf = kmalloc_node(rx_buf_sz + RX_ALIGN, GFP_KERNEL,
+                       buf = kmalloc_node(agg_buf_sz + RX_ALIGN, GFP_KERNEL,
                                           node);
                        if (!buf)
                                goto err1;
@@ -1274,13 +1277,13 @@ static int alloc_all_mem(struct r8152 *tp)
        }
 
        for (i = 0; i < RTL8152_MAX_TX; i++) {
-               buf = kmalloc_node(rx_buf_sz, GFP_KERNEL, node);
+               buf = kmalloc_node(agg_buf_sz, GFP_KERNEL, node);
                if (!buf)
                        goto err1;
 
                if (buf != tx_agg_align(buf)) {
                        kfree(buf);
-                       buf = kmalloc_node(rx_buf_sz + TX_ALIGN, GFP_KERNEL,
+                       buf = kmalloc_node(agg_buf_sz + TX_ALIGN, GFP_KERNEL,
                                           node);
                        if (!buf)
                                goto err1;
@@ -1311,8 +1314,8 @@ static int alloc_all_mem(struct r8152 *tp)
 
        tp->intr_interval = (int)ep_intr->desc.bInterval;
        usb_fill_int_urb(tp->intr_urb, tp->udev, usb_rcvintpipe(tp->udev, 3),
-                    tp->intr_buff, INTBUFSIZE, intr_callback,
-                    tp, tp->intr_interval);
+                        tp->intr_buff, INTBUFSIZE, intr_callback,
+                        tp, tp->intr_interval);
 
        return 0;
 
@@ -1354,8 +1357,7 @@ static inline __be16 get_protocol(struct sk_buff *skb)
        return protocol;
 }
 
-/*
- * r8152_csum_workaround()
+/* r8152_csum_workaround()
  * The hw limites the value the transport offset. When the offset is out of the
  * range, calculate the checksum by sw.
  */
@@ -1398,8 +1400,7 @@ drop:
        }
 }
 
-/*
- * msdn_giant_send_check()
+/* msdn_giant_send_check()
  * According to the document of microsoft, the TCP Pseudo Header excludes the
  * packet length for IPv6 TCP large packets.
  */
@@ -1518,8 +1519,9 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg)
        spin_unlock(&tx_queue->lock);
 
        tx_data = agg->head;
-       agg->skb_num = agg->skb_len = 0;
-       remain = rx_buf_sz;
+       agg->skb_num = 0;
+       agg->skb_len = 0;
+       remain = agg_buf_sz;
 
        while (remain >= ETH_ZLEN + sizeof(struct tx_desc)) {
                struct tx_desc *tx_desc;
@@ -1566,7 +1568,7 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg)
 
                dev_kfree_skb_any(skb);
 
-               remain = rx_buf_sz - (int)(tx_agg_align(tx_data) - agg->head);
+               remain = agg_buf_sz - (int)(tx_agg_align(tx_data) - agg->head);
        }
 
        if (!skb_queue_empty(&skb_head)) {
@@ -1772,8 +1774,8 @@ static
 int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags)
 {
        usb_fill_bulk_urb(agg->urb, tp->udev, usb_rcvbulkpipe(tp->udev, 1),
-                     agg->head, rx_buf_sz,
-                     (usb_complete_t)read_bulk_callback, agg);
+                         agg->head, agg_buf_sz,
+                         (usb_complete_t)read_bulk_callback, agg);
 
        return usb_submit_urb(agg->urb, mem_flags);
 }
@@ -1835,18 +1837,22 @@ static void _rtl8152_set_rx_mode(struct net_device *netdev)
                /* Unconditionally log net taps. */
                netif_notice(tp, link, netdev, "Promiscuous mode enabled\n");
                ocp_data |= RCR_AM | RCR_AAP;
-               mc_filter[1] = mc_filter[0] = 0xffffffff;
+               mc_filter[1] = 0xffffffff;
+               mc_filter[0] = 0xffffffff;
        } else if ((netdev_mc_count(netdev) > multicast_filter_limit) ||
                   (netdev->flags & IFF_ALLMULTI)) {
                /* Too many to filter perfectly -- accept all multicasts. */
                ocp_data |= RCR_AM;
-               mc_filter[1] = mc_filter[0] = 0xffffffff;
+               mc_filter[1] = 0xffffffff;
+               mc_filter[0] = 0xffffffff;
        } else {
                struct netdev_hw_addr *ha;
 
-               mc_filter[1] = mc_filter[0] = 0;
+               mc_filter[1] = 0;
+               mc_filter[0] = 0;
                netdev_for_each_mc_addr(ha, netdev) {
                        int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26;
+
                        mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
                        ocp_data |= RCR_AM;
                }
@@ -1861,7 +1867,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);
 
@@ -1877,8 +1883,9 @@ static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb,
                        usb_mark_last_busy(tp->udev);
                        tasklet_schedule(&tp->tl);
                }
-       } else if (skb_queue_len(&tp->tx_queue) > tp->tx_qlen)
+       } else if (skb_queue_len(&tp->tx_queue) > tp->tx_qlen) {
                netif_stop_queue(netdev);
+       }
 
        return NETDEV_TX_OK;
 }
@@ -1903,7 +1910,7 @@ static void rtl8152_nic_reset(struct r8152 *tp)
        for (i = 0; i < 1000; i++) {
                if (!(ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CR) & CR_RST))
                        break;
-               udelay(100);
+               usleep_range(100, 400);
        }
 }
 
@@ -1911,8 +1918,8 @@ static void set_tx_qlen(struct r8152 *tp)
 {
        struct net_device *netdev = tp->netdev;
 
-       tp->tx_qlen = rx_buf_sz / (netdev->mtu + VLAN_ETH_HLEN + VLAN_HLEN +
-                                  sizeof(struct tx_desc));
+       tp->tx_qlen = agg_buf_sz / (netdev->mtu + VLAN_ETH_HLEN + VLAN_HLEN +
+                                   sizeof(struct tx_desc));
 }
 
 static inline u8 rtl8152_get_speed(struct r8152 *tp)
@@ -2044,13 +2051,13 @@ static void rtl8152_disable(struct r8152 *tp)
                ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
                if ((ocp_data & FIFO_EMPTY) == FIFO_EMPTY)
                        break;
-               mdelay(1);
+               usleep_range(1000, 2000);
        }
 
        for (i = 0; i < 1000; i++) {
                if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR0) & TCR0_TX_EMPTY)
                        break;
-               mdelay(1);
+               usleep_range(1000, 2000);
        }
 
        for (i = 0; i < RTL8152_MAX_RX; i++)
@@ -2195,7 +2202,7 @@ static void rtl_clear_bp(struct r8152 *tp)
        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);
+       usleep_range(3000, 6000);
        ocp_write_word(tp, MCU_TYPE_PLA, PLA_BP_BA, 0);
        ocp_write_word(tp, MCU_TYPE_USB, USB_BP_BA, 0);
 }
@@ -2281,7 +2288,7 @@ static void r8152b_exit_oob(struct r8152 *tp)
                ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
                if (ocp_data & LINK_LIST_READY)
                        break;
-               mdelay(1);
+               usleep_range(1000, 2000);
        }
 
        ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
@@ -2292,7 +2299,7 @@ static void r8152b_exit_oob(struct r8152 *tp)
                ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
                if (ocp_data & LINK_LIST_READY)
                        break;
-               mdelay(1);
+               usleep_range(1000, 2000);
        }
 
        rtl8152_nic_reset(tp);
@@ -2353,7 +2360,7 @@ static void r8152b_enter_oob(struct r8152 *tp)
                ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
                if (ocp_data & LINK_LIST_READY)
                        break;
-               mdelay(1);
+               usleep_range(1000, 2000);
        }
 
        ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
@@ -2364,7 +2371,7 @@ static void r8152b_enter_oob(struct r8152 *tp)
                ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
                if (ocp_data & LINK_LIST_READY)
                        break;
-               mdelay(1);
+               usleep_range(1000, 2000);
        }
 
        ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS);
@@ -2511,7 +2518,7 @@ static void r8153_first_init(struct r8152 *tp)
                ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
                if (ocp_data & LINK_LIST_READY)
                        break;
-               mdelay(1);
+               usleep_range(1000, 2000);
        }
 
        ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
@@ -2522,7 +2529,7 @@ static void r8153_first_init(struct r8152 *tp)
                ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
                if (ocp_data & LINK_LIST_READY)
                        break;
-               mdelay(1);
+               usleep_range(1000, 2000);
        }
 
        ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CPCR);
@@ -2566,7 +2573,7 @@ static void r8153_enter_oob(struct r8152 *tp)
                ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
                if (ocp_data & LINK_LIST_READY)
                        break;
-               mdelay(1);
+               usleep_range(1000, 2000);
        }
 
        ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
@@ -2577,7 +2584,7 @@ static void r8153_enter_oob(struct r8152 *tp)
                ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
                if (ocp_data & LINK_LIST_READY)
                        break;
-               mdelay(1);
+               usleep_range(1000, 2000);
        }
 
        ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8153_RMS);
@@ -2861,8 +2868,7 @@ static int rtl8152_close(struct net_device *netdev)
        if (res < 0) {
                rtl_drop_queued_tx(tp);
        } else {
-               /*
-                * The autosuspend may have been enabled and wouldn't
+               /* The autosuspend may have been enabled and wouldn't
                 * be disable when autoresume occurs, because the
                 * netif_running() would be false.
                 */
@@ -3085,8 +3091,9 @@ static int rtl8152_resume(struct usb_interface *intf)
                } else {
                        tp->rtl_ops.up(tp);
                        rtl8152_set_speed(tp, AUTONEG_ENABLE,
-                               tp->mii.supports_gmii ? SPEED_1000 : SPEED_100,
-                               DUPLEX_FULL);
+                                         tp->mii.supports_gmii ?
+                                         SPEED_1000 : SPEED_100,
+                                         DUPLEX_FULL);
                }
                tp->speed = 0;
                netif_carrier_off(tp->netdev);
@@ -3147,8 +3154,8 @@ static void rtl8152_get_drvinfo(struct net_device *netdev,
 {
        struct r8152 *tp = netdev_priv(netdev);
 
-       strncpy(info->driver, MODULENAME, ETHTOOL_BUSINFO_LEN);
-       strncpy(info->version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
+       strlcpy(info->driver, MODULENAME, sizeof(info->driver));
+       strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));
        usb_make_path(tp->udev, info->bus_info, sizeof(info->bus_info));
 }
 
index 59caa06f34a6b3b17fa3cbce41ea3fb1b08b14a3..9359a13d285ad19bf33602f514b8275fb8e725d1 100644 (file)
@@ -934,7 +934,6 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
                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);
@@ -954,6 +953,9 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
                }
        }
 
+       if (__netif_subqueue_stopped(dev, qnum) || !skb->xmit_more)
+               virtqueue_kick(sq->vq);
+
        return NETDEV_TX_OK;
 }
 
index d6e90c72c257ebe6740d3980dc7273c6b128978d..6dfcbf523936ef69527f5d23168dbf51ee638094 100644 (file)
@@ -2056,7 +2056,6 @@ vmxnet3_set_mc(struct net_device *netdev)
                if (!netdev_mc_empty(netdev)) {
                        new_table = vmxnet3_copy_mc(netdev);
                        if (new_table) {
-                               new_mode |= VMXNET3_RXM_MCAST;
                                rxConf->mfTableLen = cpu_to_le16(
                                        netdev_mc_count(netdev) * ETH_ALEN);
                                new_table_pa = dma_map_single(
@@ -2064,15 +2063,18 @@ vmxnet3_set_mc(struct net_device *netdev)
                                                        new_table,
                                                        rxConf->mfTableLen,
                                                        PCI_DMA_TODEVICE);
+                       }
+
+                       if (new_table_pa) {
+                               new_mode |= VMXNET3_RXM_MCAST;
                                rxConf->mfTablePA = cpu_to_le64(new_table_pa);
                        } else {
-                               netdev_info(netdev, "failed to copy mcast list"
-                                           ", setting ALL_MULTI\n");
+                               netdev_info(netdev,
+                                           "failed to copy mcast list, setting ALL_MULTI\n");
                                new_mode |= VMXNET3_RXM_ALL_MULTI;
                        }
                }
 
-
        if (!(new_mode & VMXNET3_RXM_MCAST)) {
                rxConf->mfTableLen = 0;
                rxConf->mfTablePA = 0;
@@ -2091,11 +2093,10 @@ vmxnet3_set_mc(struct net_device *netdev)
                               VMXNET3_CMD_UPDATE_MAC_FILTERS);
        spin_unlock_irqrestore(&adapter->cmd_lock, flags);
 
-       if (new_table) {
+       if (new_table_pa)
                dma_unmap_single(&adapter->pdev->dev, new_table_pa,
                                 rxConf->mfTableLen, PCI_DMA_TODEVICE);
-               kfree(new_table);
-       }
+       kfree(new_table);
 }
 
 void
index 29ee77f2c97f3cc0e27e2985751297e3fbf01f90..3759479f959a43b86654e7b493a5d1beb5b6034b 100644 (file)
 /*
  * Version numbers
  */
-#define VMXNET3_DRIVER_VERSION_STRING   "1.2.0.0-k"
+#define VMXNET3_DRIVER_VERSION_STRING   "1.2.1.0-k"
 
 /* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */
-#define VMXNET3_DRIVER_VERSION_NUM      0x01020000
+#define VMXNET3_DRIVER_VERSION_NUM      0x01020100
 
 #if defined(CONFIG_PCI_MSI)
        /* RSS only makes sense if MSI-X is supported. */
index 1fb7b37d1402a447b84298829bab61d4f8b6d129..53c3ec19807cfd4b880c9bc7f4348847dd8c38c1 100644 (file)
@@ -1158,8 +1158,6 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
        if (!vs)
                goto drop;
 
-       skb_pop_rcv_encapsulation(skb);
-
        vs->rcv(vs, skb, vxh->vx_vni);
        return 0;
 
@@ -1327,7 +1325,7 @@ static int arp_reduce(struct net_device *dev, struct sk_buff *skb)
        } else if (vxlan->flags & VXLAN_F_L3MISS) {
                union vxlan_addr ipa = {
                        .sin.sin_addr.s_addr = tip,
-                       .sa.sa_family = AF_INET,
+                       .sin.sin_family = AF_INET,
                };
 
                vxlan_ip_miss(dev, &ipa);
@@ -1488,7 +1486,7 @@ static int neigh_reduce(struct net_device *dev, struct sk_buff *skb)
        } else if (vxlan->flags & VXLAN_F_L3MISS) {
                union vxlan_addr ipa = {
                        .sin6.sin6_addr = msg->target,
-                       .sa.sa_family = AF_INET6,
+                       .sin6.sin6_family = AF_INET6,
                };
 
                vxlan_ip_miss(dev, &ipa);
@@ -1521,7 +1519,7 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb)
                if (!n && (vxlan->flags & VXLAN_F_L3MISS)) {
                        union vxlan_addr ipa = {
                                .sin.sin_addr.s_addr = pip->daddr,
-                               .sa.sa_family = AF_INET,
+                               .sin.sin_family = AF_INET,
                        };
 
                        vxlan_ip_miss(dev, &ipa);
@@ -1542,7 +1540,7 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb)
                if (!n && (vxlan->flags & VXLAN_F_L3MISS)) {
                        union vxlan_addr ipa = {
                                .sin6.sin6_addr = pip6->daddr,
-                               .sa.sa_family = AF_INET6,
+                               .sin6.sin6_family = AF_INET6,
                        };
 
                        vxlan_ip_miss(dev, &ipa);
@@ -2372,6 +2370,8 @@ static struct socket *vxlan_create_sock(struct net *net, bool ipv6,
        /* Disable multicast loopback */
        inet_sk(sock->sk)->mc_loop = 0;
 
+       udp_set_convert_csum(sock->sk, true);
+
        return sock;
 }
 
index 43c9960dce1c4bd89195add029eefe26d0bfd1a6..ae6ecf4011892f4fa50861cfff6ee4bf158639fe 100644 (file)
@@ -192,8 +192,10 @@ static netdev_tx_t dlci_transmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct dlci_local *dlp = netdev_priv(dev);
 
-       if (skb)
-               dlp->slave->netdev_ops->ndo_start_xmit(skb, dlp->slave);
+       if (skb) {
+               struct netdev_queue *txq = skb_get_tx_queue(dev, skb);
+               netdev_start_xmit(skb, dlp->slave, txq, false);
+       }
        return NETDEV_TX_OK;
 }
 
index 334c2ece855a92af6576b01ec87cd47af58b8540..da92bfa76b7cf1d37e9ea819edf00c59d84e350b 100644 (file)
@@ -2423,8 +2423,6 @@ static void at76_delete_device(struct at76_priv *priv)
 
        kfree_skb(priv->rx_skb);
 
-       usb_put_dev(priv->udev);
-
        at76_dbg(DBG_PROC_ENTRY, "%s: before freeing priv/ieee80211_hw",
                 __func__);
        ieee80211_free_hw(priv->hw);
@@ -2558,6 +2556,7 @@ static void at76_disconnect(struct usb_interface *interface)
 
        wiphy_info(priv->hw->wiphy, "disconnecting\n");
        at76_delete_device(priv);
+       usb_put_dev(priv->udev);
        dev_info(&interface->dev, "disconnected\n");
 }
 
index fd9e5305e77fd263cb55ecb46ff08e6d06ca0935..c1a4ade3277280409e250f5eb4729e40a894a5d2 100644 (file)
@@ -261,6 +261,7 @@ enum ATH_DEBUG {
        ATH_DBG_MCI             = 0x00008000,
        ATH_DBG_DFS             = 0x00010000,
        ATH_DBG_WOW             = 0x00020000,
+       ATH_DBG_CHAN_CTX        = 0x00040000,
        ATH_DBG_ANY             = 0xffffffff
 };
 
index a6f5285235af04e7527ab7436ae31a63666a037f..1053bb5f2cdcb33dbc4381dfb3ac3f00dbb3a91c 100644 (file)
@@ -25,6 +25,7 @@ config ATH10K_DEBUG
 config ATH10K_DEBUGFS
        bool "Atheros ath10k debugfs support"
        depends on ATH10K
+       select RELAY
        ---help---
          Enabled debugfs support
 
index a4179f49ee1f3db7cd3882abd5972c5b2d884132..2cfb63ca9327f8e9c7417dfeb0893d0df8cdd33d 100644 (file)
@@ -10,6 +10,7 @@ ath10k_core-y += mac.o \
                 wmi.o \
                 bmi.o
 
+ath10k_core-$(CONFIG_ATH10K_DEBUGFS) += spectral.o
 ath10k_core-$(CONFIG_ATH10K_TRACING) += trace.o
 
 obj-$(CONFIG_ATH10K_PCI) += ath10k_pci.o
index 17d221abd58c0bb70d72a6fbf14f1e7422f8ced5..3d29b0875b3e0e0abf442d8f875fe39b7ddb9171 100644 (file)
@@ -22,7 +22,7 @@
 
 void ath10k_bmi_start(struct ath10k *ar)
 {
-       ath10k_dbg(ATH10K_DBG_BMI, "bmi start\n");
+       ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi start\n");
 
        ar->bmi.done_sent = false;
 }
@@ -33,10 +33,10 @@ int ath10k_bmi_done(struct ath10k *ar)
        u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.done);
        int ret;
 
-       ath10k_dbg(ATH10K_DBG_BMI, "bmi done\n");
+       ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi done\n");
 
        if (ar->bmi.done_sent) {
-               ath10k_dbg(ATH10K_DBG_BMI, "bmi skipped\n");
+               ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi skipped\n");
                return 0;
        }
 
@@ -45,7 +45,7 @@ int ath10k_bmi_done(struct ath10k *ar)
 
        ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
        if (ret) {
-               ath10k_warn("unable to write to the device: %d\n", ret);
+               ath10k_warn(ar, "unable to write to the device: %d\n", ret);
                return ret;
        }
 
@@ -61,10 +61,10 @@ int ath10k_bmi_get_target_info(struct ath10k *ar,
        u32 resplen = sizeof(resp.get_target_info);
        int ret;
 
-       ath10k_dbg(ATH10K_DBG_BMI, "bmi get target info\n");
+       ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi get target info\n");
 
        if (ar->bmi.done_sent) {
-               ath10k_warn("BMI Get Target Info Command disallowed\n");
+               ath10k_warn(ar, "BMI Get Target Info Command disallowed\n");
                return -EBUSY;
        }
 
@@ -72,12 +72,12 @@ int ath10k_bmi_get_target_info(struct ath10k *ar,
 
        ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen);
        if (ret) {
-               ath10k_warn("unable to get target info from device\n");
+               ath10k_warn(ar, "unable to get target info from device\n");
                return ret;
        }
 
        if (resplen < sizeof(resp.get_target_info)) {
-               ath10k_warn("invalid get_target_info response length (%d)\n",
+               ath10k_warn(ar, "invalid get_target_info response length (%d)\n",
                            resplen);
                return -EIO;
        }
@@ -97,11 +97,11 @@ int ath10k_bmi_read_memory(struct ath10k *ar,
        u32 rxlen;
        int ret;
 
-       ath10k_dbg(ATH10K_DBG_BMI, "bmi read address 0x%x length %d\n",
+       ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi read address 0x%x length %d\n",
                   address, length);
 
        if (ar->bmi.done_sent) {
-               ath10k_warn("command disallowed\n");
+               ath10k_warn(ar, "command disallowed\n");
                return -EBUSY;
        }
 
@@ -115,7 +115,7 @@ int ath10k_bmi_read_memory(struct ath10k *ar,
                ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen,
                                                  &resp, &rxlen);
                if (ret) {
-                       ath10k_warn("unable to read from the device (%d)\n",
+                       ath10k_warn(ar, "unable to read from the device (%d)\n",
                                    ret);
                        return ret;
                }
@@ -137,11 +137,11 @@ int ath10k_bmi_write_memory(struct ath10k *ar,
        u32 txlen;
        int ret;
 
-       ath10k_dbg(ATH10K_DBG_BMI, "bmi write address 0x%x length %d\n",
+       ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi write address 0x%x length %d\n",
                   address, length);
 
        if (ar->bmi.done_sent) {
-               ath10k_warn("command disallowed\n");
+               ath10k_warn(ar, "command disallowed\n");
                return -EBUSY;
        }
 
@@ -159,7 +159,7 @@ int ath10k_bmi_write_memory(struct ath10k *ar,
                ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, hdrlen + txlen,
                                                  NULL, NULL);
                if (ret) {
-                       ath10k_warn("unable to write to the device (%d)\n",
+                       ath10k_warn(ar, "unable to write to the device (%d)\n",
                                    ret);
                        return ret;
                }
@@ -183,11 +183,11 @@ int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 param, u32 *result)
        u32 resplen = sizeof(resp.execute);
        int ret;
 
-       ath10k_dbg(ATH10K_DBG_BMI, "bmi execute address 0x%x param 0x%x\n",
+       ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi execute address 0x%x param 0x%x\n",
                   address, param);
 
        if (ar->bmi.done_sent) {
-               ath10k_warn("command disallowed\n");
+               ath10k_warn(ar, "command disallowed\n");
                return -EBUSY;
        }
 
@@ -197,19 +197,19 @@ int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 param, u32 *result)
 
        ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen);
        if (ret) {
-               ath10k_warn("unable to read from the device\n");
+               ath10k_warn(ar, "unable to read from the device\n");
                return ret;
        }
 
        if (resplen < sizeof(resp.execute)) {
-               ath10k_warn("invalid execute response length (%d)\n",
+               ath10k_warn(ar, "invalid execute response length (%d)\n",
                            resplen);
                return -EIO;
        }
 
        *result = __le32_to_cpu(resp.execute.result);
 
-       ath10k_dbg(ATH10K_DBG_BMI, "bmi execute result 0x%x\n", *result);
+       ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi execute result 0x%x\n", *result);
 
        return 0;
 }
@@ -221,11 +221,11 @@ int ath10k_bmi_lz_data(struct ath10k *ar, const void *buffer, u32 length)
        u32 txlen;
        int ret;
 
-       ath10k_dbg(ATH10K_DBG_BMI, "bmi lz data buffer 0x%p length %d\n",
+       ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi lz data buffer 0x%p length %d\n",
                   buffer, length);
 
        if (ar->bmi.done_sent) {
-               ath10k_warn("command disallowed\n");
+               ath10k_warn(ar, "command disallowed\n");
                return -EBUSY;
        }
 
@@ -241,7 +241,7 @@ int ath10k_bmi_lz_data(struct ath10k *ar, const void *buffer, u32 length)
                ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, hdrlen + txlen,
                                                  NULL, NULL);
                if (ret) {
-                       ath10k_warn("unable to write to the device\n");
+                       ath10k_warn(ar, "unable to write to the device\n");
                        return ret;
                }
 
@@ -258,11 +258,11 @@ int ath10k_bmi_lz_stream_start(struct ath10k *ar, u32 address)
        u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.lz_start);
        int ret;
 
-       ath10k_dbg(ATH10K_DBG_BMI, "bmi lz stream start address 0x%x\n",
+       ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi lz stream start address 0x%x\n",
                   address);
 
        if (ar->bmi.done_sent) {
-               ath10k_warn("command disallowed\n");
+               ath10k_warn(ar, "command disallowed\n");
                return -EBUSY;
        }
 
@@ -271,7 +271,7 @@ int ath10k_bmi_lz_stream_start(struct ath10k *ar, u32 address)
 
        ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
        if (ret) {
-               ath10k_warn("unable to Start LZ Stream to the device\n");
+               ath10k_warn(ar, "unable to Start LZ Stream to the device\n");
                return ret;
        }
 
@@ -286,7 +286,7 @@ int ath10k_bmi_fast_download(struct ath10k *ar,
        u32 trailer_len = length - head_len;
        int ret;
 
-       ath10k_dbg(ATH10K_DBG_BMI,
+       ath10k_dbg(ar, ATH10K_DBG_BMI,
                   "bmi fast download address 0x%x buffer 0x%p length %d\n",
                   address, buffer, length);
 
index 4333107ecf37b8325c55f31569361a9b537dddc6..71eef233bd01e2f542cff7cd94520c2c05c0ff39 100644 (file)
@@ -284,13 +284,9 @@ int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state,
        int ret = 0;
 
        if (nbytes > ce_state->src_sz_max)
-               ath10k_warn("%s: send more we can (nbytes: %d, max: %d)\n",
+               ath10k_warn(ar, "%s: send more we can (nbytes: %d, max: %d)\n",
                            __func__, nbytes, ce_state->src_sz_max);
 
-       ret = ath10k_pci_wake(ar);
-       if (ret)
-               return ret;
-
        if (unlikely(CE_RING_DELTA(nentries_mask,
                                   write_index, sw_index - 1) <= 0)) {
                ret = -ENOSR;
@@ -325,7 +321,6 @@ int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state,
 
        src_ring->write_index = write_index;
 exit:
-       ath10k_pci_sleep(ar);
        return ret;
 }
 
@@ -390,49 +385,57 @@ int ath10k_ce_num_free_src_entries(struct ath10k_ce_pipe *pipe)
        return delta;
 }
 
-int ath10k_ce_recv_buf_enqueue(struct ath10k_ce_pipe *ce_state,
-                              void *per_recv_context,
-                              u32 buffer)
+
+int __ath10k_ce_rx_num_free_bufs(struct ath10k_ce_pipe *pipe)
 {
-       struct ath10k_ce_ring *dest_ring = ce_state->dest_ring;
-       u32 ctrl_addr = ce_state->ctrl_addr;
-       struct ath10k *ar = ce_state->ar;
+       struct ath10k *ar = pipe->ar;
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+       struct ath10k_ce_ring *dest_ring = pipe->dest_ring;
        unsigned int nentries_mask = dest_ring->nentries_mask;
-       unsigned int write_index;
-       unsigned int sw_index;
-       int ret;
+       unsigned int write_index = dest_ring->write_index;
+       unsigned int sw_index = dest_ring->sw_index;
 
-       spin_lock_bh(&ar_pci->ce_lock);
-       write_index = dest_ring->write_index;
-       sw_index = dest_ring->sw_index;
+       lockdep_assert_held(&ar_pci->ce_lock);
 
-       ret = ath10k_pci_wake(ar);
-       if (ret)
-               goto out;
+       return CE_RING_DELTA(nentries_mask, write_index, sw_index - 1);
+}
 
-       if (CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) > 0) {
-               struct ce_desc *base = dest_ring->base_addr_owner_space;
-               struct ce_desc *desc = CE_DEST_RING_TO_DESC(base, write_index);
+int __ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr)
+{
+       struct ath10k *ar = pipe->ar;
+       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+       struct ath10k_ce_ring *dest_ring = pipe->dest_ring;
+       unsigned int nentries_mask = dest_ring->nentries_mask;
+       unsigned int write_index = dest_ring->write_index;
+       unsigned int sw_index = dest_ring->sw_index;
+       struct ce_desc *base = dest_ring->base_addr_owner_space;
+       struct ce_desc *desc = CE_DEST_RING_TO_DESC(base, write_index);
+       u32 ctrl_addr = pipe->ctrl_addr;
 
-               /* Update destination descriptor */
-               desc->addr    = __cpu_to_le32(buffer);
-               desc->nbytes = 0;
+       lockdep_assert_held(&ar_pci->ce_lock);
 
-               dest_ring->per_transfer_context[write_index] =
-                                                       per_recv_context;
+       if (CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) == 0)
+               return -EIO;
 
-               /* Update Destination Ring Write Index */
-               write_index = CE_RING_IDX_INCR(nentries_mask, write_index);
-               ath10k_ce_dest_ring_write_index_set(ar, ctrl_addr, write_index);
-               dest_ring->write_index = write_index;
-               ret = 0;
-       } else {
-               ret = -EIO;
-       }
-       ath10k_pci_sleep(ar);
+       desc->addr = __cpu_to_le32(paddr);
+       desc->nbytes = 0;
+
+       dest_ring->per_transfer_context[write_index] = ctx;
+       write_index = CE_RING_IDX_INCR(nentries_mask, write_index);
+       ath10k_ce_dest_ring_write_index_set(ar, ctrl_addr, write_index);
+       dest_ring->write_index = write_index;
+
+       return 0;
+}
+
+int ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr)
+{
+       struct ath10k *ar = pipe->ar;
+       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+       int ret;
 
-out:
+       spin_lock_bh(&ar_pci->ce_lock);
+       ret = __ath10k_ce_rx_post_buf(pipe, ctx, paddr);
        spin_unlock_bh(&ar_pci->ce_lock);
 
        return ret;
@@ -588,7 +591,6 @@ static int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state,
        unsigned int sw_index = src_ring->sw_index;
        struct ce_desc *sdesc, *sbase;
        unsigned int read_index;
-       int ret;
 
        if (src_ring->hw_index == sw_index) {
                /*
@@ -599,18 +601,12 @@ static int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state,
                 * value of the HW index has become stale.
                 */
 
-               ret = ath10k_pci_wake(ar);
-               if (ret)
-                       return ret;
-
                read_index = ath10k_ce_src_ring_read_index_get(ar, ctrl_addr);
                if (read_index == 0xffffffff)
                        return -ENODEV;
 
                read_index &= nentries_mask;
                src_ring->hw_index = read_index;
-
-               ath10k_pci_sleep(ar);
        }
 
        read_index = src_ring->hw_index;
@@ -731,11 +727,6 @@ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id)
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
        struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
        u32 ctrl_addr = ce_state->ctrl_addr;
-       int ret;
-
-       ret = ath10k_pci_wake(ar);
-       if (ret)
-               return;
 
        spin_lock_bh(&ar_pci->ce_lock);
 
@@ -760,7 +751,6 @@ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id)
        ath10k_ce_engine_int_status_clear(ar, ctrl_addr, CE_WATERMARK_MASK);
 
        spin_unlock_bh(&ar_pci->ce_lock);
-       ath10k_pci_sleep(ar);
 }
 
 /*
@@ -771,13 +761,9 @@ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id)
 
 void ath10k_ce_per_engine_service_any(struct ath10k *ar)
 {
-       int ce_id, ret;
+       int ce_id;
        u32 intr_summary;
 
-       ret = ath10k_pci_wake(ar);
-       if (ret)
-               return;
-
        intr_summary = CE_INTERRUPT_SUMMARY(ar);
 
        for (ce_id = 0; intr_summary && (ce_id < CE_COUNT); ce_id++) {
@@ -789,8 +775,6 @@ void ath10k_ce_per_engine_service_any(struct ath10k *ar)
 
                ath10k_ce_per_engine_service(ar, ce_id);
        }
-
-       ath10k_pci_sleep(ar);
 }
 
 /*
@@ -800,16 +784,11 @@ void ath10k_ce_per_engine_service_any(struct ath10k *ar)
  *
  * Called with ce_lock held.
  */
-static void ath10k_ce_per_engine_handler_adjust(struct ath10k_ce_pipe *ce_state,
-                                               int disable_copy_compl_intr)
+static void ath10k_ce_per_engine_handler_adjust(struct ath10k_ce_pipe *ce_state)
 {
        u32 ctrl_addr = ce_state->ctrl_addr;
        struct ath10k *ar = ce_state->ar;
-       int ret;
-
-       ret = ath10k_pci_wake(ar);
-       if (ret)
-               return;
+       bool disable_copy_compl_intr = ce_state->attr_flags & CE_ATTR_DIS_INTR;
 
        if ((!disable_copy_compl_intr) &&
            (ce_state->send_cb || ce_state->recv_cb))
@@ -818,17 +797,11 @@ static void ath10k_ce_per_engine_handler_adjust(struct ath10k_ce_pipe *ce_state,
                ath10k_ce_copy_complete_intr_disable(ar, ctrl_addr);
 
        ath10k_ce_watermark_intr_disable(ar, ctrl_addr);
-
-       ath10k_pci_sleep(ar);
 }
 
 int ath10k_ce_disable_interrupts(struct ath10k *ar)
 {
-       int ce_id, ret;
-
-       ret = ath10k_pci_wake(ar);
-       if (ret)
-               return ret;
+       int ce_id;
 
        for (ce_id = 0; ce_id < CE_COUNT; ce_id++) {
                u32 ctrl_addr = ath10k_ce_base_address(ce_id);
@@ -838,34 +811,16 @@ int ath10k_ce_disable_interrupts(struct ath10k *ar)
                ath10k_ce_watermark_intr_disable(ar, ctrl_addr);
        }
 
-       ath10k_pci_sleep(ar);
-
        return 0;
 }
 
-void ath10k_ce_send_cb_register(struct ath10k_ce_pipe *ce_state,
-                               void (*send_cb)(struct ath10k_ce_pipe *),
-                               int disable_interrupts)
+void ath10k_ce_enable_interrupts(struct ath10k *ar)
 {
-       struct ath10k *ar = ce_state->ar;
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+       int ce_id;
 
-       spin_lock_bh(&ar_pci->ce_lock);
-       ce_state->send_cb = send_cb;
-       ath10k_ce_per_engine_handler_adjust(ce_state, disable_interrupts);
-       spin_unlock_bh(&ar_pci->ce_lock);
-}
-
-void ath10k_ce_recv_cb_register(struct ath10k_ce_pipe *ce_state,
-                               void (*recv_cb)(struct ath10k_ce_pipe *))
-{
-       struct ath10k *ar = ce_state->ar;
-       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-
-       spin_lock_bh(&ar_pci->ce_lock);
-       ce_state->recv_cb = recv_cb;
-       ath10k_ce_per_engine_handler_adjust(ce_state, 0);
-       spin_unlock_bh(&ar_pci->ce_lock);
+       for (ce_id = 0; ce_id < CE_COUNT; ce_id++)
+               ath10k_ce_per_engine_handler_adjust(&ar_pci->ce_states[ce_id]);
 }
 
 static int ath10k_ce_init_src_ring(struct ath10k *ar,
@@ -898,7 +853,7 @@ static int ath10k_ce_init_src_ring(struct ath10k *ar,
        ath10k_ce_src_ring_lowmark_set(ar, ctrl_addr, 0);
        ath10k_ce_src_ring_highmark_set(ar, ctrl_addr, nentries);
 
-       ath10k_dbg(ATH10K_DBG_BOOT,
+       ath10k_dbg(ar, ATH10K_DBG_BOOT,
                   "boot init ce src ring id %d entries %d base_addr %p\n",
                   ce_id, nentries, src_ring->base_addr_owner_space);
 
@@ -932,7 +887,7 @@ static int ath10k_ce_init_dest_ring(struct ath10k *ar,
        ath10k_ce_dest_ring_lowmark_set(ar, ctrl_addr, 0);
        ath10k_ce_dest_ring_highmark_set(ar, ctrl_addr, nentries);
 
-       ath10k_dbg(ATH10K_DBG_BOOT,
+       ath10k_dbg(ar, ATH10K_DBG_BOOT,
                   "boot ce dest ring id %d entries %d base_addr %p\n",
                   ce_id, nentries, dest_ring->base_addr_owner_space);
 
@@ -1067,7 +1022,9 @@ ath10k_ce_alloc_dest_ring(struct ath10k *ar, unsigned int ce_id,
  * initialized by software/firmware.
  */
 int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id,
-                       const struct ce_attr *attr)
+                       const struct ce_attr *attr,
+                       void (*send_cb)(struct ath10k_ce_pipe *),
+                       void (*recv_cb)(struct ath10k_ce_pipe *))
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
        struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
@@ -1084,39 +1041,37 @@ int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id,
        BUILD_BUG_ON(2*TARGET_10X_NUM_MSDU_DESC >
                     (CE_HTT_H2T_MSG_SRC_NENTRIES - 1));
 
-       ret = ath10k_pci_wake(ar);
-       if (ret)
-               return ret;
-
        spin_lock_bh(&ar_pci->ce_lock);
        ce_state->ar = ar;
        ce_state->id = ce_id;
        ce_state->ctrl_addr = ath10k_ce_base_address(ce_id);
        ce_state->attr_flags = attr->flags;
        ce_state->src_sz_max = attr->src_sz_max;
+       if (attr->src_nentries)
+               ce_state->send_cb = send_cb;
+       if (attr->dest_nentries)
+               ce_state->recv_cb = recv_cb;
        spin_unlock_bh(&ar_pci->ce_lock);
 
        if (attr->src_nentries) {
                ret = ath10k_ce_init_src_ring(ar, ce_id, attr);
                if (ret) {
-                       ath10k_err("Failed to initialize CE src ring for ID: %d (%d)\n",
+                       ath10k_err(ar, "Failed to initialize CE src ring for ID: %d (%d)\n",
                                   ce_id, ret);
-                       goto out;
+                       return ret;
                }
        }
 
        if (attr->dest_nentries) {
                ret = ath10k_ce_init_dest_ring(ar, ce_id, attr);
                if (ret) {
-                       ath10k_err("Failed to initialize CE dest ring for ID: %d (%d)\n",
+                       ath10k_err(ar, "Failed to initialize CE dest ring for ID: %d (%d)\n",
                                   ce_id, ret);
-                       goto out;
+                       return ret;
                }
        }
 
-out:
-       ath10k_pci_sleep(ar);
-       return ret;
+       return 0;
 }
 
 static void ath10k_ce_deinit_src_ring(struct ath10k *ar, unsigned int ce_id)
@@ -1140,16 +1095,8 @@ static void ath10k_ce_deinit_dest_ring(struct ath10k *ar, unsigned int ce_id)
 
 void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id)
 {
-       int ret;
-
-       ret = ath10k_pci_wake(ar);
-       if (ret)
-               return;
-
        ath10k_ce_deinit_src_ring(ar, ce_id);
        ath10k_ce_deinit_dest_ring(ar, ce_id);
-
-       ath10k_pci_sleep(ar);
 }
 
 int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id,
@@ -1163,7 +1110,7 @@ int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id,
                ce_state->src_ring = ath10k_ce_alloc_src_ring(ar, ce_id, attr);
                if (IS_ERR(ce_state->src_ring)) {
                        ret = PTR_ERR(ce_state->src_ring);
-                       ath10k_err("failed to allocate copy engine source ring %d: %d\n",
+                       ath10k_err(ar, "failed to allocate copy engine source ring %d: %d\n",
                                   ce_id, ret);
                        ce_state->src_ring = NULL;
                        return ret;
@@ -1175,7 +1122,7 @@ int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id,
                                                                attr);
                if (IS_ERR(ce_state->dest_ring)) {
                        ret = PTR_ERR(ce_state->dest_ring);
-                       ath10k_err("failed to allocate copy engine destination ring %d: %d\n",
+                       ath10k_err(ar, "failed to allocate copy engine destination ring %d: %d\n",
                                   ce_id, ret);
                        ce_state->dest_ring = NULL;
                        return ret;
index 7a5a36fc59c1ad19c51e2c69496660f75aeca073..82d1f23546b9e343db6d7ad0960083ff185281e6 100644 (file)
@@ -162,30 +162,13 @@ int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state,
 
 void __ath10k_ce_send_revert(struct ath10k_ce_pipe *pipe);
 
-void ath10k_ce_send_cb_register(struct ath10k_ce_pipe *ce_state,
-                               void (*send_cb)(struct ath10k_ce_pipe *),
-                               int disable_interrupts);
-
 int ath10k_ce_num_free_src_entries(struct ath10k_ce_pipe *pipe);
 
 /*==================Recv=======================*/
 
-/*
- * Make a buffer available to receive. The buffer must be at least of a
- * minimal size appropriate for this copy engine (src_sz_max attribute).
- *   ce                    - which copy engine to use
- *   per_transfer_recv_context  - context passed back to caller's recv_cb
- *   buffer                     - address of buffer in CE space
- * Returns 0 on success; otherwise an error status.
- *
- * Implemenation note: Pushes a buffer to Dest ring.
- */
-int ath10k_ce_recv_buf_enqueue(struct ath10k_ce_pipe *ce_state,
-                              void *per_transfer_recv_context,
-                              u32 buffer);
-
-void ath10k_ce_recv_cb_register(struct ath10k_ce_pipe *ce_state,
-                               void (*recv_cb)(struct ath10k_ce_pipe *));
+int __ath10k_ce_rx_num_free_bufs(struct ath10k_ce_pipe *pipe);
+int __ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr);
+int ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr);
 
 /* recv flags */
 /* Data is byte-swapped */
@@ -214,7 +197,9 @@ int ath10k_ce_completed_send_next(struct ath10k_ce_pipe *ce_state,
 /*==================CE Engine Initialization=======================*/
 
 int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id,
-                       const struct ce_attr *attr);
+                       const struct ce_attr *attr,
+                       void (*send_cb)(struct ath10k_ce_pipe *),
+                       void (*recv_cb)(struct ath10k_ce_pipe *));
 void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id);
 int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id,
                          const struct ce_attr *attr);
@@ -245,6 +230,7 @@ int ath10k_ce_cancel_send_next(struct ath10k_ce_pipe *ce_state,
 void ath10k_ce_per_engine_service_any(struct ath10k *ar);
 void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id);
 int ath10k_ce_disable_interrupts(struct ath10k *ar);
+void ath10k_ce_enable_interrupts(struct ath10k *ar);
 
 /* ce_attr.flags values */
 /* Use NonSnooping PCIe accesses? */
index 93adb8c5896926c787bb80e6c0869cd7f5fd4672..651a6da8adf5544de4c254b5511a8cad5cb568de 100644 (file)
@@ -53,7 +53,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
 
 static void ath10k_send_suspend_complete(struct ath10k *ar)
 {
-       ath10k_dbg(ATH10K_DBG_BOOT, "boot suspend complete\n");
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot suspend complete\n");
 
        complete(&ar->target_suspend);
 }
@@ -67,14 +67,14 @@ static int ath10k_init_configure_target(struct ath10k *ar)
        ret = ath10k_bmi_write32(ar, hi_app_host_interest,
                                 HTC_PROTOCOL_VERSION);
        if (ret) {
-               ath10k_err("settings HTC version failed\n");
+               ath10k_err(ar, "settings HTC version failed\n");
                return ret;
        }
 
        /* set the firmware mode to STA/IBSS/AP */
        ret = ath10k_bmi_read32(ar, hi_option_flag, &param_host);
        if (ret) {
-               ath10k_err("setting firmware mode (1/2) failed\n");
+               ath10k_err(ar, "setting firmware mode (1/2) failed\n");
                return ret;
        }
 
@@ -93,14 +93,14 @@ static int ath10k_init_configure_target(struct ath10k *ar)
 
        ret = ath10k_bmi_write32(ar, hi_option_flag, param_host);
        if (ret) {
-               ath10k_err("setting firmware mode (2/2) failed\n");
+               ath10k_err(ar, "setting firmware mode (2/2) failed\n");
                return ret;
        }
 
        /* We do all byte-swapping on the host */
        ret = ath10k_bmi_write32(ar, hi_be, 0);
        if (ret) {
-               ath10k_err("setting host CPU BE mode failed\n");
+               ath10k_err(ar, "setting host CPU BE mode failed\n");
                return ret;
        }
 
@@ -108,7 +108,7 @@ static int ath10k_init_configure_target(struct ath10k *ar)
        ret = ath10k_bmi_write32(ar, hi_fw_swap, 0);
 
        if (ret) {
-               ath10k_err("setting FW data/desc swap flags failed\n");
+               ath10k_err(ar, "setting FW data/desc swap flags failed\n");
                return ret;
        }
 
@@ -146,11 +146,12 @@ static int ath10k_push_board_ext_data(struct ath10k *ar)
 
        ret = ath10k_bmi_read32(ar, hi_board_ext_data, &board_ext_data_addr);
        if (ret) {
-               ath10k_err("could not read board ext data addr (%d)\n", ret);
+               ath10k_err(ar, "could not read board ext data addr (%d)\n",
+                          ret);
                return ret;
        }
 
-       ath10k_dbg(ATH10K_DBG_BOOT,
+       ath10k_dbg(ar, ATH10K_DBG_BOOT,
                   "boot push board extended data addr 0x%x\n",
                   board_ext_data_addr);
 
@@ -158,7 +159,7 @@ static int ath10k_push_board_ext_data(struct ath10k *ar)
                return 0;
 
        if (ar->board_len != (board_data_size + board_ext_data_size)) {
-               ath10k_err("invalid board (ext) data sizes %zu != %d+%d\n",
+               ath10k_err(ar, "invalid board (ext) data sizes %zu != %d+%d\n",
                           ar->board_len, board_data_size, board_ext_data_size);
                return -EINVAL;
        }
@@ -167,14 +168,15 @@ static int ath10k_push_board_ext_data(struct ath10k *ar)
                                      ar->board_data + board_data_size,
                                      board_ext_data_size);
        if (ret) {
-               ath10k_err("could not write board ext data (%d)\n", ret);
+               ath10k_err(ar, "could not write board ext data (%d)\n", ret);
                return ret;
        }
 
        ret = ath10k_bmi_write32(ar, hi_board_ext_data_config,
                                 (board_ext_data_size << 16) | 1);
        if (ret) {
-               ath10k_err("could not write board ext data bit (%d)\n", ret);
+               ath10k_err(ar, "could not write board ext data bit (%d)\n",
+                          ret);
                return ret;
        }
 
@@ -189,13 +191,13 @@ static int ath10k_download_board_data(struct ath10k *ar)
 
        ret = ath10k_push_board_ext_data(ar);
        if (ret) {
-               ath10k_err("could not push board ext data (%d)\n", ret);
+               ath10k_err(ar, "could not push board ext data (%d)\n", ret);
                goto exit;
        }
 
        ret = ath10k_bmi_read32(ar, hi_board_data, &address);
        if (ret) {
-               ath10k_err("could not read board data addr (%d)\n", ret);
+               ath10k_err(ar, "could not read board data addr (%d)\n", ret);
                goto exit;
        }
 
@@ -203,13 +205,13 @@ static int ath10k_download_board_data(struct ath10k *ar)
                                      min_t(u32, board_data_size,
                                            ar->board_len));
        if (ret) {
-               ath10k_err("could not write board data (%d)\n", ret);
+               ath10k_err(ar, "could not write board data (%d)\n", ret);
                goto exit;
        }
 
        ret = ath10k_bmi_write32(ar, hi_board_data_initialized, 1);
        if (ret) {
-               ath10k_err("could not write board data bit (%d)\n", ret);
+               ath10k_err(ar, "could not write board data bit (%d)\n", ret);
                goto exit;
        }
 
@@ -225,30 +227,30 @@ static int ath10k_download_and_run_otp(struct ath10k *ar)
        /* OTP is optional */
 
        if (!ar->otp_data || !ar->otp_len) {
-               ath10k_warn("Not running otp, calibration will be incorrect (otp-data %p otp_len %zd)!\n",
+               ath10k_warn(ar, "Not running otp, calibration will be incorrect (otp-data %p otp_len %zd)!\n",
                            ar->otp_data, ar->otp_len);
                return 0;
        }
 
-       ath10k_dbg(ATH10K_DBG_BOOT, "boot upload otp to 0x%x len %zd\n",
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot upload otp to 0x%x len %zd\n",
                   address, ar->otp_len);
 
        ret = ath10k_bmi_fast_download(ar, address, ar->otp_data, ar->otp_len);
        if (ret) {
-               ath10k_err("could not write otp (%d)\n", ret);
+               ath10k_err(ar, "could not write otp (%d)\n", ret);
                return ret;
        }
 
        ret = ath10k_bmi_execute(ar, address, 0, &result);
        if (ret) {
-               ath10k_err("could not execute otp (%d)\n", ret);
+               ath10k_err(ar, "could not execute otp (%d)\n", ret);
                return ret;
        }
 
-       ath10k_dbg(ATH10K_DBG_BOOT, "boot otp execute result %d\n", result);
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot otp execute result %d\n", result);
 
        if (result != 0) {
-               ath10k_err("otp calibration failed: %d", result);
+               ath10k_err(ar, "otp calibration failed: %d", result);
                return -EINVAL;
        }
 
@@ -265,7 +267,7 @@ static int ath10k_download_fw(struct ath10k *ar)
        ret = ath10k_bmi_fast_download(ar, address, ar->firmware_data,
                                       ar->firmware_len);
        if (ret) {
-               ath10k_err("could not write fw (%d)\n", ret);
+               ath10k_err(ar, "could not write fw (%d)\n", ret);
                goto exit;
        }
 
@@ -302,12 +304,12 @@ static int ath10k_core_fetch_firmware_api_1(struct ath10k *ar)
        int ret = 0;
 
        if (ar->hw_params.fw.fw == NULL) {
-               ath10k_err("firmware file not defined\n");
+               ath10k_err(ar, "firmware file not defined\n");
                return -EINVAL;
        }
 
        if (ar->hw_params.fw.board == NULL) {
-               ath10k_err("board data file not defined");
+               ath10k_err(ar, "board data file not defined");
                return -EINVAL;
        }
 
@@ -316,7 +318,7 @@ static int ath10k_core_fetch_firmware_api_1(struct ath10k *ar)
                                         ar->hw_params.fw.board);
        if (IS_ERR(ar->board)) {
                ret = PTR_ERR(ar->board);
-               ath10k_err("could not fetch board data (%d)\n", ret);
+               ath10k_err(ar, "could not fetch board data (%d)\n", ret);
                goto err;
        }
 
@@ -328,7 +330,7 @@ static int ath10k_core_fetch_firmware_api_1(struct ath10k *ar)
                                            ar->hw_params.fw.fw);
        if (IS_ERR(ar->firmware)) {
                ret = PTR_ERR(ar->firmware);
-               ath10k_err("could not fetch firmware (%d)\n", ret);
+               ath10k_err(ar, "could not fetch firmware (%d)\n", ret);
                goto err;
        }
 
@@ -344,7 +346,7 @@ static int ath10k_core_fetch_firmware_api_1(struct ath10k *ar)
                                       ar->hw_params.fw.otp);
        if (IS_ERR(ar->otp)) {
                ret = PTR_ERR(ar->otp);
-               ath10k_err("could not fetch otp (%d)\n", ret);
+               ath10k_err(ar, "could not fetch otp (%d)\n", ret);
                goto err;
        }
 
@@ -369,7 +371,7 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
        /* first fetch the firmware file (firmware-*.bin) */
        ar->firmware = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, name);
        if (IS_ERR(ar->firmware)) {
-               ath10k_err("could not fetch firmware file '%s/%s': %ld\n",
+               ath10k_err(ar, "could not fetch firmware file '%s/%s': %ld\n",
                           ar->hw_params.fw.dir, name, PTR_ERR(ar->firmware));
                return PTR_ERR(ar->firmware);
        }
@@ -381,14 +383,14 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
        magic_len = strlen(ATH10K_FIRMWARE_MAGIC) + 1;
 
        if (len < magic_len) {
-               ath10k_err("firmware file '%s/%s' too small to contain magic: %zu\n",
+               ath10k_err(ar, "firmware file '%s/%s' too small to contain magic: %zu\n",
                           ar->hw_params.fw.dir, name, len);
                ret = -EINVAL;
                goto err;
        }
 
        if (memcmp(data, ATH10K_FIRMWARE_MAGIC, magic_len) != 0) {
-               ath10k_err("invalid firmware magic\n");
+               ath10k_err(ar, "invalid firmware magic\n");
                ret = -EINVAL;
                goto err;
        }
@@ -410,7 +412,7 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
                data += sizeof(*hdr);
 
                if (len < ie_len) {
-                       ath10k_err("invalid length for FW IE %d (%zu < %zu)\n",
+                       ath10k_err(ar, "invalid length for FW IE %d (%zu < %zu)\n",
                                   ie_id, len, ie_len);
                        ret = -EINVAL;
                        goto err;
@@ -424,7 +426,7 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
                        memcpy(ar->hw->wiphy->fw_version, data, ie_len);
                        ar->hw->wiphy->fw_version[ie_len] = '\0';
 
-                       ath10k_dbg(ATH10K_DBG_BOOT,
+                       ath10k_dbg(ar, ATH10K_DBG_BOOT,
                                   "found fw version %s\n",
                                    ar->hw->wiphy->fw_version);
                        break;
@@ -434,11 +436,11 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
 
                        timestamp = (__le32 *)data;
 
-                       ath10k_dbg(ATH10K_DBG_BOOT, "found fw timestamp %d\n",
+                       ath10k_dbg(ar, ATH10K_DBG_BOOT, "found fw timestamp %d\n",
                                   le32_to_cpup(timestamp));
                        break;
                case ATH10K_FW_IE_FEATURES:
-                       ath10k_dbg(ATH10K_DBG_BOOT,
+                       ath10k_dbg(ar, ATH10K_DBG_BOOT,
                                   "found firmware features ie (%zd B)\n",
                                   ie_len);
 
@@ -450,19 +452,19 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
                                        break;
 
                                if (data[index] & (1 << bit)) {
-                                       ath10k_dbg(ATH10K_DBG_BOOT,
+                                       ath10k_dbg(ar, ATH10K_DBG_BOOT,
                                                   "Enabling feature bit: %i\n",
                                                   i);
                                        __set_bit(i, ar->fw_features);
                                }
                        }
 
-                       ath10k_dbg_dump(ATH10K_DBG_BOOT, "features", "",
+                       ath10k_dbg_dump(ar, ATH10K_DBG_BOOT, "features", "",
                                        ar->fw_features,
                                        sizeof(ar->fw_features));
                        break;
                case ATH10K_FW_IE_FW_IMAGE:
-                       ath10k_dbg(ATH10K_DBG_BOOT,
+                       ath10k_dbg(ar, ATH10K_DBG_BOOT,
                                   "found fw image ie (%zd B)\n",
                                   ie_len);
 
@@ -471,7 +473,7 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
 
                        break;
                case ATH10K_FW_IE_OTP_IMAGE:
-                       ath10k_dbg(ATH10K_DBG_BOOT,
+                       ath10k_dbg(ar, ATH10K_DBG_BOOT,
                                   "found otp image ie (%zd B)\n",
                                   ie_len);
 
@@ -480,7 +482,7 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
 
                        break;
                default:
-                       ath10k_warn("Unknown FW IE: %u\n",
+                       ath10k_warn(ar, "Unknown FW IE: %u\n",
                                    le32_to_cpu(hdr->id));
                        break;
                }
@@ -493,15 +495,22 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
        }
 
        if (!ar->firmware_data || !ar->firmware_len) {
-               ath10k_warn("No ATH10K_FW_IE_FW_IMAGE found from '%s/%s', skipping\n",
+               ath10k_warn(ar, "No ATH10K_FW_IE_FW_IMAGE found from '%s/%s', skipping\n",
                            ar->hw_params.fw.dir, name);
                ret = -ENOMEDIUM;
                goto err;
        }
 
+       if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features) &&
+           !test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
+               ath10k_err(ar, "feature bits corrupted: 10.2 feature requires 10.x feature to be set as well");
+               ret = -EINVAL;
+               goto err;
+       }
+
        /* now fetch the board file */
        if (ar->hw_params.fw.board == NULL) {
-               ath10k_err("board data file not defined");
+               ath10k_err(ar, "board data file not defined");
                ret = -EINVAL;
                goto err;
        }
@@ -511,7 +520,7 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
                                         ar->hw_params.fw.board);
        if (IS_ERR(ar->board)) {
                ret = PTR_ERR(ar->board);
-               ath10k_err("could not fetch board data '%s/%s' (%d)\n",
+               ath10k_err(ar, "could not fetch board data '%s/%s' (%d)\n",
                           ar->hw_params.fw.dir, ar->hw_params.fw.board,
                           ret);
                goto err;
@@ -531,22 +540,29 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar)
 {
        int ret;
 
+       ar->fw_api = 3;
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
+
+       ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API3_FILE);
+       if (ret == 0)
+               goto success;
+
        ar->fw_api = 2;
-       ath10k_dbg(ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
 
        ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API2_FILE);
        if (ret == 0)
                goto success;
 
        ar->fw_api = 1;
-       ath10k_dbg(ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
 
        ret = ath10k_core_fetch_firmware_api_1(ar);
        if (ret)
                return ret;
 
 success:
-       ath10k_dbg(ATH10K_DBG_BOOT, "using fw api %d\n", ar->fw_api);
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "using fw api %d\n", ar->fw_api);
 
        return 0;
 }
@@ -557,19 +573,19 @@ static int ath10k_init_download_firmware(struct ath10k *ar)
 
        ret = ath10k_download_board_data(ar);
        if (ret) {
-               ath10k_err("failed to download board data: %d\n", ret);
+               ath10k_err(ar, "failed to download board data: %d\n", ret);
                return ret;
        }
 
        ret = ath10k_download_and_run_otp(ar);
        if (ret) {
-               ath10k_err("failed to run otp: %d\n", ret);
+               ath10k_err(ar, "failed to run otp: %d\n", ret);
                return ret;
        }
 
        ret = ath10k_download_fw(ar);
        if (ret) {
-               ath10k_err("failed to download firmware: %d\n", ret);
+               ath10k_err(ar, "failed to download firmware: %d\n", ret);
                return ret;
        }
 
@@ -586,7 +602,7 @@ static int ath10k_init_uart(struct ath10k *ar)
         */
        ret = ath10k_bmi_write32(ar, hi_serial_enable, 0);
        if (ret) {
-               ath10k_warn("could not disable UART prints (%d)\n", ret);
+               ath10k_warn(ar, "could not disable UART prints (%d)\n", ret);
                return ret;
        }
 
@@ -595,24 +611,24 @@ static int ath10k_init_uart(struct ath10k *ar)
 
        ret = ath10k_bmi_write32(ar, hi_dbg_uart_txpin, 7);
        if (ret) {
-               ath10k_warn("could not enable UART prints (%d)\n", ret);
+               ath10k_warn(ar, "could not enable UART prints (%d)\n", ret);
                return ret;
        }
 
        ret = ath10k_bmi_write32(ar, hi_serial_enable, 1);
        if (ret) {
-               ath10k_warn("could not enable UART prints (%d)\n", ret);
+               ath10k_warn(ar, "could not enable UART prints (%d)\n", ret);
                return ret;
        }
 
        /* Set the UART baud rate to 19200. */
        ret = ath10k_bmi_write32(ar, hi_desired_baud_rate, 19200);
        if (ret) {
-               ath10k_warn("could not set the baud rate (%d)\n", ret);
+               ath10k_warn(ar, "could not set the baud rate (%d)\n", ret);
                return ret;
        }
 
-       ath10k_info("UART prints enabled\n");
+       ath10k_info(ar, "UART prints enabled\n");
        return 0;
 }
 
@@ -629,14 +645,14 @@ static int ath10k_init_hw_params(struct ath10k *ar)
        }
 
        if (i == ARRAY_SIZE(ath10k_hw_params_list)) {
-               ath10k_err("Unsupported hardware version: 0x%x\n",
+               ath10k_err(ar, "Unsupported hardware version: 0x%x\n",
                           ar->target_version);
                return -EINVAL;
        }
 
        ar->hw_params = *hw_params;
 
-       ath10k_dbg(ATH10K_DBG_BOOT, "Hardware name %s version 0x%x\n",
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "Hardware name %s version 0x%x\n",
                   ar->hw_params.name, ar->target_version);
 
        return 0;
@@ -651,14 +667,14 @@ static void ath10k_core_restart(struct work_struct *work)
        switch (ar->state) {
        case ATH10K_STATE_ON:
                ar->state = ATH10K_STATE_RESTARTING;
-               del_timer_sync(&ar->scan.timeout);
-               ath10k_reset_scan((unsigned long)ar);
+               ath10k_hif_stop(ar);
+               ath10k_scan_finish(ar);
                ieee80211_restart_hw(ar->hw);
                break;
        case ATH10K_STATE_OFF:
                /* this can happen if driver is being unloaded
                 * or if the crash happens during FW probing */
-               ath10k_warn("cannot restart a device that hasn't been started\n");
+               ath10k_warn(ar, "cannot restart a device that hasn't been started\n");
                break;
        case ATH10K_STATE_RESTARTING:
                /* hw restart might be requested from multiple places */
@@ -667,7 +683,7 @@ static void ath10k_core_restart(struct work_struct *work)
                ar->state = ATH10K_STATE_WEDGED;
                /* fall through */
        case ATH10K_STATE_WEDGED:
-               ath10k_warn("device is wedged, will not restart\n");
+               ath10k_warn(ar, "device is wedged, will not restart\n");
                break;
        }
 
@@ -700,7 +716,7 @@ int ath10k_core_start(struct ath10k *ar)
 
        status = ath10k_htc_init(ar);
        if (status) {
-               ath10k_err("could not init HTC (%d)\n", status);
+               ath10k_err(ar, "could not init HTC (%d)\n", status);
                goto err;
        }
 
@@ -710,90 +726,91 @@ int ath10k_core_start(struct ath10k *ar)
 
        status = ath10k_wmi_attach(ar);
        if (status) {
-               ath10k_err("WMI attach failed: %d\n", status);
+               ath10k_err(ar, "WMI attach failed: %d\n", status);
                goto err;
        }
 
        status = ath10k_htt_init(ar);
        if (status) {
-               ath10k_err("failed to init htt: %d\n", status);
+               ath10k_err(ar, "failed to init htt: %d\n", status);
                goto err_wmi_detach;
        }
 
        status = ath10k_htt_tx_alloc(&ar->htt);
        if (status) {
-               ath10k_err("failed to alloc htt tx: %d\n", status);
+               ath10k_err(ar, "failed to alloc htt tx: %d\n", status);
                goto err_wmi_detach;
        }
 
        status = ath10k_htt_rx_alloc(&ar->htt);
        if (status) {
-               ath10k_err("failed to alloc htt rx: %d\n", status);
+               ath10k_err(ar, "failed to alloc htt rx: %d\n", status);
                goto err_htt_tx_detach;
        }
 
        status = ath10k_hif_start(ar);
        if (status) {
-               ath10k_err("could not start HIF: %d\n", status);
+               ath10k_err(ar, "could not start HIF: %d\n", status);
                goto err_htt_rx_detach;
        }
 
        status = ath10k_htc_wait_target(&ar->htc);
        if (status) {
-               ath10k_err("failed to connect to HTC: %d\n", status);
+               ath10k_err(ar, "failed to connect to HTC: %d\n", status);
                goto err_hif_stop;
        }
 
        status = ath10k_htt_connect(&ar->htt);
        if (status) {
-               ath10k_err("failed to connect htt (%d)\n", status);
+               ath10k_err(ar, "failed to connect htt (%d)\n", status);
                goto err_hif_stop;
        }
 
        status = ath10k_wmi_connect(ar);
        if (status) {
-               ath10k_err("could not connect wmi: %d\n", status);
+               ath10k_err(ar, "could not connect wmi: %d\n", status);
                goto err_hif_stop;
        }
 
        status = ath10k_htc_start(&ar->htc);
        if (status) {
-               ath10k_err("failed to start htc: %d\n", status);
+               ath10k_err(ar, "failed to start htc: %d\n", status);
                goto err_hif_stop;
        }
 
        status = ath10k_wmi_wait_for_service_ready(ar);
        if (status <= 0) {
-               ath10k_warn("wmi service ready event not received");
+               ath10k_warn(ar, "wmi service ready event not received");
                status = -ETIMEDOUT;
-               goto err_htc_stop;
+               goto err_hif_stop;
        }
 
-       ath10k_dbg(ATH10K_DBG_BOOT, "firmware %s booted\n",
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "firmware %s booted\n",
                   ar->hw->wiphy->fw_version);
 
        status = ath10k_wmi_cmd_init(ar);
        if (status) {
-               ath10k_err("could not send WMI init command (%d)\n", status);
-               goto err_htc_stop;
+               ath10k_err(ar, "could not send WMI init command (%d)\n",
+                          status);
+               goto err_hif_stop;
        }
 
        status = ath10k_wmi_wait_for_unified_ready(ar);
        if (status <= 0) {
-               ath10k_err("wmi unified ready event not received\n");
+               ath10k_err(ar, "wmi unified ready event not received\n");
                status = -ETIMEDOUT;
-               goto err_htc_stop;
+               goto err_hif_stop;
        }
 
        status = ath10k_htt_setup(&ar->htt);
        if (status) {
-               ath10k_err("failed to setup htt: %d\n", status);
-               goto err_htc_stop;
+               ath10k_err(ar, "failed to setup htt: %d\n", status);
+               goto err_hif_stop;
        }
 
        status = ath10k_debug_start(ar);
        if (status)
-               goto err_htc_stop;
+               goto err_hif_stop;
 
        if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
                ar->free_vdev_map = (1 << TARGET_10X_NUM_VDEVS) - 1;
@@ -802,28 +819,8 @@ int ath10k_core_start(struct ath10k *ar)
 
        INIT_LIST_HEAD(&ar->arvifs);
 
-       if (!test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags)) {
-               ath10k_info("%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d\n",
-                           ar->hw_params.name,
-                           ar->target_version,
-                           ar->chip_id,
-                           ar->hw->wiphy->fw_version,
-                           ar->fw_api,
-                           ar->htt.target_version_major,
-                           ar->htt.target_version_minor);
-               ath10k_info("debug %d debugfs %d tracing %d dfs %d\n",
-                           config_enabled(CONFIG_ATH10K_DEBUG),
-                           config_enabled(CONFIG_ATH10K_DEBUGFS),
-                           config_enabled(CONFIG_ATH10K_TRACING),
-                           config_enabled(CONFIG_ATH10K_DFS_CERTIFIED));
-       }
-
-       __set_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags);
-
        return 0;
 
-err_htc_stop:
-       ath10k_htc_stop(&ar->htc);
 err_hif_stop:
        ath10k_hif_stop(ar);
 err_htt_rx_detach:
@@ -845,14 +842,14 @@ int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt)
 
        ret = ath10k_wmi_pdev_suspend_target(ar, suspend_opt);
        if (ret) {
-               ath10k_warn("could not suspend target (%d)\n", ret);
+               ath10k_warn(ar, "could not suspend target (%d)\n", ret);
                return ret;
        }
 
        ret = wait_for_completion_timeout(&ar->target_suspend, 1 * HZ);
 
        if (ret == 0) {
-               ath10k_warn("suspend timed out - target pause event never came\n");
+               ath10k_warn(ar, "suspend timed out - target pause event never came\n");
                return -ETIMEDOUT;
        }
 
@@ -868,7 +865,6 @@ void ath10k_core_stop(struct ath10k *ar)
                ath10k_wait_for_suspend(ar, WMI_PDEV_SUSPEND_AND_DISABLE_INTR);
 
        ath10k_debug_stop(ar);
-       ath10k_htc_stop(&ar->htc);
        ath10k_hif_stop(ar);
        ath10k_htt_tx_free(&ar->htt);
        ath10k_htt_rx_free(&ar->htt);
@@ -887,14 +883,14 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
 
        ret = ath10k_hif_power_up(ar);
        if (ret) {
-               ath10k_err("could not start pci hif (%d)\n", ret);
+               ath10k_err(ar, "could not start pci hif (%d)\n", ret);
                return ret;
        }
 
        memset(&target_info, 0, sizeof(target_info));
        ret = ath10k_bmi_get_target_info(ar, &target_info);
        if (ret) {
-               ath10k_err("could not get target info (%d)\n", ret);
+               ath10k_err(ar, "could not get target info (%d)\n", ret);
                ath10k_hif_power_down(ar);
                return ret;
        }
@@ -904,14 +900,14 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
 
        ret = ath10k_init_hw_params(ar);
        if (ret) {
-               ath10k_err("could not get hw params (%d)\n", ret);
+               ath10k_err(ar, "could not get hw params (%d)\n", ret);
                ath10k_hif_power_down(ar);
                return ret;
        }
 
        ret = ath10k_core_fetch_firmware_files(ar);
        if (ret) {
-               ath10k_err("could not fetch firmware files (%d)\n", ret);
+               ath10k_err(ar, "could not fetch firmware files (%d)\n", ret);
                ath10k_hif_power_down(ar);
                return ret;
        }
@@ -920,13 +916,14 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
 
        ret = ath10k_core_start(ar);
        if (ret) {
-               ath10k_err("could not init core (%d)\n", ret);
+               ath10k_err(ar, "could not init core (%d)\n", ret);
                ath10k_core_free_firmware_files(ar);
                ath10k_hif_power_down(ar);
                mutex_unlock(&ar->conf_mutex);
                return ret;
        }
 
+       ath10k_print_driver_info(ar);
        ath10k_core_stop(ar);
 
        mutex_unlock(&ar->conf_mutex);
@@ -939,7 +936,7 @@ static int ath10k_core_check_chip_id(struct ath10k *ar)
 {
        u32 hw_revision = MS(ar->chip_id, SOC_CHIP_ID_REV);
 
-       ath10k_dbg(ATH10K_DBG_BOOT, "boot chip_id 0x%08x hw_revision 0x%x\n",
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot chip_id 0x%08x hw_revision 0x%x\n",
                   ar->chip_id, hw_revision);
 
        /* Check that we are not using hw1.0 (some of them have same pci id
@@ -947,7 +944,7 @@ static int ath10k_core_check_chip_id(struct ath10k *ar)
         * due to missing hw1.0 workarounds. */
        switch (hw_revision) {
        case QCA988X_HW_1_0_CHIP_ID_REV:
-               ath10k_err("ERROR: qca988x hw1.0 is not supported\n");
+               ath10k_err(ar, "ERROR: qca988x hw1.0 is not supported\n");
                return -EOPNOTSUPP;
 
        case QCA988X_HW_2_0_CHIP_ID_REV:
@@ -955,7 +952,7 @@ static int ath10k_core_check_chip_id(struct ath10k *ar)
                return 0;
 
        default:
-               ath10k_warn("Warning: hardware revision unknown (0x%x), expect problems\n",
+               ath10k_warn(ar, "Warning: hardware revision unknown (0x%x), expect problems\n",
                            ar->chip_id);
                return 0;
        }
@@ -970,25 +967,33 @@ static void ath10k_core_register_work(struct work_struct *work)
 
        status = ath10k_core_probe_fw(ar);
        if (status) {
-               ath10k_err("could not probe fw (%d)\n", status);
+               ath10k_err(ar, "could not probe fw (%d)\n", status);
                goto err;
        }
 
        status = ath10k_mac_register(ar);
        if (status) {
-               ath10k_err("could not register to mac80211 (%d)\n", status);
+               ath10k_err(ar, "could not register to mac80211 (%d)\n", status);
                goto err_release_fw;
        }
 
        status = ath10k_debug_create(ar);
        if (status) {
-               ath10k_err("unable to initialize debugfs\n");
+               ath10k_err(ar, "unable to initialize debugfs\n");
                goto err_unregister_mac;
        }
 
+       status = ath10k_spectral_create(ar);
+       if (status) {
+               ath10k_err(ar, "failed to initialize spectral\n");
+               goto err_debug_destroy;
+       }
+
        set_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags);
        return;
 
+err_debug_destroy:
+       ath10k_debug_destroy(ar);
 err_unregister_mac:
        ath10k_mac_unregister(ar);
 err_release_fw:
@@ -1008,7 +1013,7 @@ int ath10k_core_register(struct ath10k *ar, u32 chip_id)
 
        status = ath10k_core_check_chip_id(ar);
        if (status) {
-               ath10k_err("Unsupported chip id 0x%08x\n", ar->chip_id);
+               ath10k_err(ar, "Unsupported chip id 0x%08x\n", ar->chip_id);
                return status;
        }
 
@@ -1025,6 +1030,12 @@ void ath10k_core_unregister(struct ath10k *ar)
        if (!test_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags))
                return;
 
+       /* Stop spectral before unregistering from mac80211 to remove the
+        * relayfs debugfs file cleanly. Otherwise the parent debugfs tree
+        * would be already be free'd recursively, leading to a double free.
+        */
+       ath10k_spectral_destroy(ar);
+
        /* We must unregister from mac80211 before we stop HTC and HIF.
         * Otherwise we will fail to submit commands to FW and mac80211 will be
         * unhappy about callback failures. */
@@ -1036,12 +1047,12 @@ void ath10k_core_unregister(struct ath10k *ar)
 }
 EXPORT_SYMBOL(ath10k_core_unregister);
 
-struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
+struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
                                  const struct ath10k_hif_ops *hif_ops)
 {
        struct ath10k *ar;
 
-       ar = ath10k_mac_create();
+       ar = ath10k_mac_create(priv_size);
        if (!ar)
                return NULL;
 
@@ -1051,7 +1062,6 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
        ar->p2p = !!ath10k_p2p;
        ar->dev = dev;
 
-       ar->hif.priv = hif_priv;
        ar->hif.ops = hif_ops;
 
        init_completion(&ar->scan.started);
@@ -1062,7 +1072,7 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
        init_completion(&ar->install_key_done);
        init_completion(&ar->vdev_setup_done);
 
-       setup_timer(&ar->scan.timeout, ath10k_reset_scan, (unsigned long)ar);
+       INIT_DELAYED_WORK(&ar->scan.timeout, ath10k_scan_timeout_work);
 
        ar->workqueue = create_singlethread_workqueue("ath10k_wq");
        if (!ar->workqueue)
index 83a5fa91531d159b9095ef0fff37db55c38e0eeb..4ef476099225775567b4ade0a45e227e855b4d1d 100644 (file)
@@ -22,6 +22,8 @@
 #include <linux/if_ether.h>
 #include <linux/types.h>
 #include <linux/pci.h>
+#include <linux/uuid.h>
+#include <linux/time.h>
 
 #include "htt.h"
 #include "htc.h"
@@ -31,6 +33,7 @@
 #include "../ath.h"
 #include "../regd.h"
 #include "../dfs_pattern_detector.h"
+#include "spectral.h"
 
 #define MS(_v, _f) (((_v) & _f##_MASK) >> _f##_LSB)
 #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK)
@@ -237,6 +240,7 @@ struct ath10k_vif {
 
        bool is_started;
        bool is_up;
+       bool spectral_enabled;
        u32 aid;
        u8 bssid[ETH_ALEN];
 
@@ -276,11 +280,20 @@ struct ath10k_vif_iter {
        struct ath10k_vif *arvif;
 };
 
+/* used for crash-dump storage, protected by data-lock */
+struct ath10k_fw_crash_data {
+       bool crashed_since_read;
+
+       uuid_le uuid;
+       struct timespec timestamp;
+       __le32 registers[REG_DUMP_COUNT_QCA988X];
+};
+
 struct ath10k_debug {
        struct dentry *debugfs_phy;
 
        struct ath10k_target_stats target_stats;
-       u32 wmi_service_bitmap[WMI_SERVICE_BM_SIZE];
+       DECLARE_BITMAP(wmi_service_bitmap, WMI_SERVICE_BM_SIZE);
 
        struct completion event_stats_compl;
 
@@ -293,6 +306,8 @@ struct ath10k_debug {
 
        u8 htt_max_amsdu;
        u8 htt_max_ampdu;
+
+       struct ath10k_fw_crash_data *fw_crash_data;
 };
 
 enum ath10k_state {
@@ -330,6 +345,11 @@ enum ath10k_fw_features {
        /* Firmware does not support P2P */
        ATH10K_FW_FEATURE_NO_P2P = 3,
 
+       /* Firmware 10.2 feature bit. The ATH10K_FW_FEATURE_WMI_10X feature bit
+        * is required to be set as well.
+        */
+       ATH10K_FW_FEATURE_WMI_10_2 = 4,
+
        /* keep last */
        ATH10K_FW_FEATURE_COUNT,
 };
@@ -337,10 +357,32 @@ enum ath10k_fw_features {
 enum ath10k_dev_flags {
        /* Indicates that ath10k device is during CAC phase of DFS */
        ATH10K_CAC_RUNNING,
-       ATH10K_FLAG_FIRST_BOOT_DONE,
        ATH10K_FLAG_CORE_REGISTERED,
 };
 
+enum ath10k_scan_state {
+       ATH10K_SCAN_IDLE,
+       ATH10K_SCAN_STARTING,
+       ATH10K_SCAN_RUNNING,
+       ATH10K_SCAN_ABORTING,
+};
+
+static inline const char *ath10k_scan_state_str(enum ath10k_scan_state state)
+{
+       switch (state) {
+       case ATH10K_SCAN_IDLE:
+               return "idle";
+       case ATH10K_SCAN_STARTING:
+               return "starting";
+       case ATH10K_SCAN_RUNNING:
+               return "running";
+       case ATH10K_SCAN_ABORTING:
+               return "aborting";
+       }
+
+       return "unknown";
+}
+
 struct ath10k {
        struct ath_common ath_common;
        struct ieee80211_hw *hw;
@@ -368,7 +410,6 @@ struct ath10k {
        bool p2p;
 
        struct {
-               void *priv;
                const struct ath10k_hif_ops *ops;
        } hif;
 
@@ -410,10 +451,9 @@ struct ath10k {
                struct completion started;
                struct completion completed;
                struct completion on_channel;
-               struct timer_list timeout;
+               struct delayed_work timeout;
+               enum ath10k_scan_state state;
                bool is_roc;
-               bool in_progress;
-               bool aborting;
                int vdev_id;
                int roc_freq;
        } scan;
@@ -494,9 +534,21 @@ struct ath10k {
 #ifdef CONFIG_ATH10K_DEBUGFS
        struct ath10k_debug debug;
 #endif
+
+       struct {
+               /* relay(fs) channel for spectral scan */
+               struct rchan *rfs_chan_spec_scan;
+
+               /* spectral_mode and spec_config are protected by conf_mutex */
+               enum ath10k_spectral_mode mode;
+               struct ath10k_spec_scan config;
+       } spectral;
+
+       /* must be last */
+       u8 drv_priv[0] __aligned(sizeof(void *));
 };
 
-struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev,
+struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
                                  const struct ath10k_hif_ops *hif_ops);
 void ath10k_core_destroy(struct ath10k *ar);
 
index 3030158c478e86cd9ee193af14b29da614f0d168..f3f0a80f8bab3eac6996b03629941d670f378456 100644 (file)
@@ -17,6 +17,9 @@
 
 #include <linux/module.h>
 #include <linux/debugfs.h>
+#include <linux/version.h>
+#include <linux/vermagic.h>
+#include <linux/vmalloc.h>
 
 #include "core.h"
 #include "debug.h"
 /* ms */
 #define ATH10K_DEBUG_HTT_STATS_INTERVAL 1000
 
-static int ath10k_printk(const char *level, const char *fmt, ...)
-{
-       struct va_format vaf;
-       va_list args;
-       int rtn;
+#define ATH10K_FW_CRASH_DUMP_VERSION 1
 
-       va_start(args, fmt);
+/**
+ * enum ath10k_fw_crash_dump_type - types of data in the dump file
+ * @ATH10K_FW_CRASH_DUMP_REGDUMP: Register crash dump in binary format
+ */
+enum ath10k_fw_crash_dump_type {
+       ATH10K_FW_CRASH_DUMP_REGISTERS = 0,
 
-       vaf.fmt = fmt;
-       vaf.va = &args;
+       ATH10K_FW_CRASH_DUMP_MAX,
+};
 
-       rtn = printk("%sath10k: %pV", level, &vaf);
+struct ath10k_tlv_dump_data {
+       /* see ath10k_fw_crash_dump_type above */
+       __le32 type;
 
-       va_end(args);
+       /* in bytes */
+       __le32 tlv_len;
 
-       return rtn;
-}
+       /* pad to 32-bit boundaries as needed */
+       u8 tlv_data[];
+} __packed;
+
+struct ath10k_dump_file_data {
+       /* dump file information */
+
+       /* "ATH10K-FW-DUMP" */
+       char df_magic[16];
+
+       __le32 len;
+
+       /* file dump version */
+       __le32 version;
+
+       /* some info we can get from ath10k struct that might help */
+
+       u8 uuid[16];
+
+       __le32 chip_id;
+
+       /* 0 for now, in place for later hardware */
+       __le32 bus_type;
+
+       __le32 target_version;
+       __le32 fw_version_major;
+       __le32 fw_version_minor;
+       __le32 fw_version_release;
+       __le32 fw_version_build;
+       __le32 phy_capability;
+       __le32 hw_min_tx_power;
+       __le32 hw_max_tx_power;
+       __le32 ht_cap_info;
+       __le32 vht_cap_info;
+       __le32 num_rf_chains;
+
+       /* firmware version string */
+       char fw_ver[ETHTOOL_FWVERS_LEN];
+
+       /* Kernel related information */
+
+       /* time-of-day stamp */
+       __le64 tv_sec;
 
-int ath10k_info(const char *fmt, ...)
+       /* time-of-day stamp, nano-seconds */
+       __le64 tv_nsec;
+
+       /* LINUX_VERSION_CODE */
+       __le32 kernel_ver_code;
+
+       /* VERMAGIC_STRING */
+       char kernel_ver[64];
+
+       /* room for growth w/out changing binary format */
+       u8 unused[128];
+
+       /* struct ath10k_tlv_dump_data + more */
+       u8 data[0];
+} __packed;
+
+int ath10k_info(struct ath10k *ar, const char *fmt, ...)
 {
        struct va_format vaf = {
                .fmt = fmt,
@@ -52,7 +116,7 @@ int ath10k_info(const char *fmt, ...)
 
        va_start(args, fmt);
        vaf.va = &args;
-       ret = ath10k_printk(KERN_INFO, "%pV", &vaf);
+       ret = dev_info(ar->dev, "%pV", &vaf);
        trace_ath10k_log_info(&vaf);
        va_end(args);
 
@@ -60,7 +124,25 @@ int ath10k_info(const char *fmt, ...)
 }
 EXPORT_SYMBOL(ath10k_info);
 
-int ath10k_err(const char *fmt, ...)
+void ath10k_print_driver_info(struct ath10k *ar)
+{
+       ath10k_info(ar, "%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d\n",
+                   ar->hw_params.name,
+                   ar->target_version,
+                   ar->chip_id,
+                   ar->hw->wiphy->fw_version,
+                   ar->fw_api,
+                   ar->htt.target_version_major,
+                   ar->htt.target_version_minor);
+       ath10k_info(ar, "debug %d debugfs %d tracing %d dfs %d\n",
+                   config_enabled(CONFIG_ATH10K_DEBUG),
+                   config_enabled(CONFIG_ATH10K_DEBUGFS),
+                   config_enabled(CONFIG_ATH10K_TRACING),
+                   config_enabled(CONFIG_ATH10K_DFS_CERTIFIED));
+}
+EXPORT_SYMBOL(ath10k_print_driver_info);
+
+int ath10k_err(struct ath10k *ar, const char *fmt, ...)
 {
        struct va_format vaf = {
                .fmt = fmt,
@@ -70,7 +152,7 @@ int ath10k_err(const char *fmt, ...)
 
        va_start(args, fmt);
        vaf.va = &args;
-       ret = ath10k_printk(KERN_ERR, "%pV", &vaf);
+       ret = dev_err(ar->dev, "%pV", &vaf);
        trace_ath10k_log_err(&vaf);
        va_end(args);
 
@@ -78,25 +160,21 @@ int ath10k_err(const char *fmt, ...)
 }
 EXPORT_SYMBOL(ath10k_err);
 
-int ath10k_warn(const char *fmt, ...)
+int ath10k_warn(struct ath10k *ar, const char *fmt, ...)
 {
        struct va_format vaf = {
                .fmt = fmt,
        };
        va_list args;
-       int ret = 0;
 
        va_start(args, fmt);
        vaf.va = &args;
-
-       if (net_ratelimit())
-               ret = ath10k_printk(KERN_WARNING, "%pV", &vaf);
-
+       dev_warn_ratelimited(ar->dev, "%pV", &vaf);
        trace_ath10k_log_warn(&vaf);
 
        va_end(args);
 
-       return ret;
+       return 0;
 }
 EXPORT_SYMBOL(ath10k_warn);
 
@@ -115,9 +193,10 @@ static ssize_t ath10k_read_wmi_services(struct file *file,
 {
        struct ath10k *ar = file->private_data;
        char *buf;
-       unsigned int len = 0, buf_len = 1500;
-       const char *status;
+       unsigned int len = 0, buf_len = 4096;
+       const char *name;
        ssize_t ret_cnt;
+       bool enabled;
        int i;
 
        buf = kzalloc(buf_len, GFP_KERNEL);
@@ -129,15 +208,22 @@ static ssize_t ath10k_read_wmi_services(struct file *file,
        if (len > buf_len)
                len = buf_len;
 
-       for (i = 0; i < WMI_SERVICE_LAST; i++) {
-               if (WMI_SERVICE_IS_ENABLED(ar->debug.wmi_service_bitmap, i))
-                       status = "enabled";
-               else
-                       status = "disabled";
+       for (i = 0; i < WMI_MAX_SERVICE; i++) {
+               enabled = test_bit(i, ar->debug.wmi_service_bitmap);
+               name = wmi_service_name(i);
+
+               if (!name) {
+                       if (enabled)
+                               len += scnprintf(buf + len, buf_len - len,
+                                                "%-40s %s (bit %d)\n",
+                                                "unknown", "enabled", i);
+
+                       continue;
+               }
 
                len += scnprintf(buf + len, buf_len - len,
-                                "0x%02x - %20s - %s\n",
-                                i, wmi_service_name(i), status);
+                                "%-40s %s\n",
+                                name, enabled ? "enabled" : "-");
        }
 
        ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
@@ -309,7 +395,7 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf,
 
        ret = ath10k_wmi_request_stats(ar, WMI_REQUEST_PEER_STAT);
        if (ret) {
-               ath10k_warn("could not request stats (%d)\n", ret);
+               ath10k_warn(ar, "could not request stats (%d)\n", ret);
                goto exit;
        }
 
@@ -527,11 +613,14 @@ static ssize_t ath10k_write_simulate_fw_crash(struct file *file,
        }
 
        if (!strcmp(buf, "soft")) {
-               ath10k_info("simulating soft firmware crash\n");
+               ath10k_info(ar, "simulating soft firmware crash\n");
                ret = ath10k_wmi_force_fw_hang(ar, WMI_FORCE_FW_HANG_ASSERT, 0);
        } else if (!strcmp(buf, "hard")) {
-               ath10k_info("simulating hard firmware crash\n");
-               ret = ath10k_wmi_vdev_set_param(ar, TARGET_NUM_VDEVS + 1,
+               ath10k_info(ar, "simulating hard firmware crash\n");
+               /* 0x7fff is vdev id, and it is always out of range for all
+                * firmware variants in order to force a firmware crash.
+                */
+               ret = ath10k_wmi_vdev_set_param(ar, 0x7fff,
                                        ar->wmi.vdev_param->rts_threshold, 0);
        } else {
                ret = -EINVAL;
@@ -539,7 +628,7 @@ static ssize_t ath10k_write_simulate_fw_crash(struct file *file,
        }
 
        if (ret) {
-               ath10k_warn("failed to simulate firmware crash: %d\n", ret);
+               ath10k_warn(ar, "failed to simulate firmware crash: %d\n", ret);
                goto exit;
        }
 
@@ -577,6 +666,138 @@ static const struct file_operations fops_chip_id = {
        .llseek = default_llseek,
 };
 
+struct ath10k_fw_crash_data *
+ath10k_debug_get_new_fw_crash_data(struct ath10k *ar)
+{
+       struct ath10k_fw_crash_data *crash_data = ar->debug.fw_crash_data;
+
+       lockdep_assert_held(&ar->data_lock);
+
+       crash_data->crashed_since_read = true;
+       uuid_le_gen(&crash_data->uuid);
+       getnstimeofday(&crash_data->timestamp);
+
+       return crash_data;
+}
+EXPORT_SYMBOL(ath10k_debug_get_new_fw_crash_data);
+
+static struct ath10k_dump_file_data *ath10k_build_dump_file(struct ath10k *ar)
+{
+       struct ath10k_fw_crash_data *crash_data = ar->debug.fw_crash_data;
+       struct ath10k_dump_file_data *dump_data;
+       struct ath10k_tlv_dump_data *dump_tlv;
+       int hdr_len = sizeof(*dump_data);
+       unsigned int len, sofar = 0;
+       unsigned char *buf;
+
+       len = hdr_len;
+       len += sizeof(*dump_tlv) + sizeof(crash_data->registers);
+
+       sofar += hdr_len;
+
+       /* This is going to get big when we start dumping FW RAM and such,
+        * so go ahead and use vmalloc.
+        */
+       buf = vzalloc(len);
+       if (!buf)
+               return NULL;
+
+       spin_lock_bh(&ar->data_lock);
+
+       if (!crash_data->crashed_since_read) {
+               spin_unlock_bh(&ar->data_lock);
+               vfree(buf);
+               return NULL;
+       }
+
+       dump_data = (struct ath10k_dump_file_data *)(buf);
+       strlcpy(dump_data->df_magic, "ATH10K-FW-DUMP",
+               sizeof(dump_data->df_magic));
+       dump_data->len = cpu_to_le32(len);
+
+       dump_data->version = cpu_to_le32(ATH10K_FW_CRASH_DUMP_VERSION);
+
+       memcpy(dump_data->uuid, &crash_data->uuid, sizeof(dump_data->uuid));
+       dump_data->chip_id = cpu_to_le32(ar->chip_id);
+       dump_data->bus_type = cpu_to_le32(0);
+       dump_data->target_version = cpu_to_le32(ar->target_version);
+       dump_data->fw_version_major = cpu_to_le32(ar->fw_version_major);
+       dump_data->fw_version_minor = cpu_to_le32(ar->fw_version_minor);
+       dump_data->fw_version_release = cpu_to_le32(ar->fw_version_release);
+       dump_data->fw_version_build = cpu_to_le32(ar->fw_version_build);
+       dump_data->phy_capability = cpu_to_le32(ar->phy_capability);
+       dump_data->hw_min_tx_power = cpu_to_le32(ar->hw_min_tx_power);
+       dump_data->hw_max_tx_power = cpu_to_le32(ar->hw_max_tx_power);
+       dump_data->ht_cap_info = cpu_to_le32(ar->ht_cap_info);
+       dump_data->vht_cap_info = cpu_to_le32(ar->vht_cap_info);
+       dump_data->num_rf_chains = cpu_to_le32(ar->num_rf_chains);
+
+       strlcpy(dump_data->fw_ver, ar->hw->wiphy->fw_version,
+               sizeof(dump_data->fw_ver));
+
+       dump_data->kernel_ver_code = cpu_to_le32(LINUX_VERSION_CODE);
+       strlcpy(dump_data->kernel_ver, VERMAGIC_STRING,
+               sizeof(dump_data->kernel_ver));
+
+       dump_data->tv_sec = cpu_to_le64(crash_data->timestamp.tv_sec);
+       dump_data->tv_nsec = cpu_to_le64(crash_data->timestamp.tv_nsec);
+
+       /* Gather crash-dump */
+       dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar);
+       dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_REGISTERS);
+       dump_tlv->tlv_len = cpu_to_le32(sizeof(crash_data->registers));
+       memcpy(dump_tlv->tlv_data, &crash_data->registers,
+              sizeof(crash_data->registers));
+       sofar += sizeof(*dump_tlv) + sizeof(crash_data->registers);
+
+       ar->debug.fw_crash_data->crashed_since_read = false;
+
+       spin_unlock_bh(&ar->data_lock);
+
+       return dump_data;
+}
+
+static int ath10k_fw_crash_dump_open(struct inode *inode, struct file *file)
+{
+       struct ath10k *ar = inode->i_private;
+       struct ath10k_dump_file_data *dump;
+
+       dump = ath10k_build_dump_file(ar);
+       if (!dump)
+               return -ENODATA;
+
+       file->private_data = dump;
+
+       return 0;
+}
+
+static ssize_t ath10k_fw_crash_dump_read(struct file *file,
+                                        char __user *user_buf,
+                                        size_t count, loff_t *ppos)
+{
+       struct ath10k_dump_file_data *dump_file = file->private_data;
+
+       return simple_read_from_buffer(user_buf, count, ppos,
+                                      dump_file,
+                                      le32_to_cpu(dump_file->len));
+}
+
+static int ath10k_fw_crash_dump_release(struct inode *inode,
+                                       struct file *file)
+{
+       vfree(file->private_data);
+
+       return 0;
+}
+
+static const struct file_operations fops_fw_crash_dump = {
+       .open = ath10k_fw_crash_dump_open,
+       .read = ath10k_fw_crash_dump_read,
+       .release = ath10k_fw_crash_dump_release,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
 static int ath10k_debug_htt_stats_req(struct ath10k *ar)
 {
        u64 cookie;
@@ -596,7 +817,7 @@ static int ath10k_debug_htt_stats_req(struct ath10k *ar)
        ret = ath10k_htt_h2t_stats_req(&ar->htt, ar->debug.htt_stats_mask,
                                       cookie);
        if (ret) {
-               ath10k_warn("failed to send htt stats request: %d\n", ret);
+               ath10k_warn(ar, "failed to send htt stats request: %d\n", ret);
                return ret;
        }
 
@@ -770,7 +991,7 @@ static ssize_t ath10k_write_fw_dbglog(struct file *file,
        if (ar->state == ATH10K_STATE_ON) {
                ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask);
                if (ret) {
-                       ath10k_warn("dbglog cfg failed from debugfs: %d\n",
+                       ath10k_warn(ar, "dbglog cfg failed from debugfs: %d\n",
                                    ret);
                        goto exit;
                }
@@ -801,13 +1022,14 @@ int ath10k_debug_start(struct ath10k *ar)
        ret = ath10k_debug_htt_stats_req(ar);
        if (ret)
                /* continue normally anyway, this isn't serious */
-               ath10k_warn("failed to start htt stats workqueue: %d\n", ret);
+               ath10k_warn(ar, "failed to start htt stats workqueue: %d\n",
+                           ret);
 
        if (ar->debug.fw_dbglog_mask) {
                ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask);
                if (ret)
                        /* not serious */
-                       ath10k_warn("failed to enable dbglog during start: %d",
+                       ath10k_warn(ar, "failed to enable dbglog during start: %d",
                                    ret);
        }
 
@@ -910,11 +1132,20 @@ static const struct file_operations fops_dfs_stats = {
 
 int ath10k_debug_create(struct ath10k *ar)
 {
+       int ret;
+
+       ar->debug.fw_crash_data = vzalloc(sizeof(*ar->debug.fw_crash_data));
+       if (!ar->debug.fw_crash_data) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
        ar->debug.debugfs_phy = debugfs_create_dir("ath10k",
                                                   ar->hw->wiphy->debugfsdir);
-
-       if (!ar->debug.debugfs_phy)
-               return -ENOMEM;
+       if (!ar->debug.debugfs_phy) {
+               ret = -ENOMEM;
+               goto err_free_fw_crash_data;
+       }
 
        INIT_DELAYED_WORK(&ar->debug.htt_stats_dwork,
                          ath10k_debug_htt_stats_dwork);
@@ -930,6 +1161,9 @@ int ath10k_debug_create(struct ath10k *ar)
        debugfs_create_file("simulate_fw_crash", S_IRUSR, ar->debug.debugfs_phy,
                            ar, &fops_simulate_fw_crash);
 
+       debugfs_create_file("fw_crash_dump", S_IRUSR, ar->debug.debugfs_phy,
+                           ar, &fops_fw_crash_dump);
+
        debugfs_create_file("chip_id", S_IRUSR, ar->debug.debugfs_phy,
                            ar, &fops_chip_id);
 
@@ -958,17 +1192,25 @@ int ath10k_debug_create(struct ath10k *ar)
        }
 
        return 0;
+
+err_free_fw_crash_data:
+       vfree(ar->debug.fw_crash_data);
+
+err:
+       return ret;
 }
 
 void ath10k_debug_destroy(struct ath10k *ar)
 {
+       vfree(ar->debug.fw_crash_data);
        cancel_delayed_work_sync(&ar->debug.htt_stats_dwork);
 }
 
 #endif /* CONFIG_ATH10K_DEBUGFS */
 
 #ifdef CONFIG_ATH10K_DEBUG
-void ath10k_dbg(enum ath10k_debug_mask mask, const char *fmt, ...)
+void ath10k_dbg(struct ath10k *ar, enum ath10k_debug_mask mask,
+               const char *fmt, ...)
 {
        struct va_format vaf;
        va_list args;
@@ -979,7 +1221,7 @@ void ath10k_dbg(enum ath10k_debug_mask mask, const char *fmt, ...)
        vaf.va = &args;
 
        if (ath10k_debug_mask & mask)
-               ath10k_printk(KERN_DEBUG, "%pV", &vaf);
+               dev_printk(KERN_DEBUG, ar->dev, "%pV", &vaf);
 
        trace_ath10k_log_dbg(mask, &vaf);
 
@@ -987,13 +1229,14 @@ void ath10k_dbg(enum ath10k_debug_mask mask, const char *fmt, ...)
 }
 EXPORT_SYMBOL(ath10k_dbg);
 
-void ath10k_dbg_dump(enum ath10k_debug_mask mask,
+void ath10k_dbg_dump(struct ath10k *ar,
+                    enum ath10k_debug_mask mask,
                     const char *msg, const char *prefix,
                     const void *buf, size_t len)
 {
        if (ath10k_debug_mask & mask) {
                if (msg)
-                       ath10k_dbg(mask, "%s\n", msg);
+                       ath10k_dbg(ar, mask, "%s\n", msg);
 
                print_hex_dump_bytes(prefix, DUMP_PREFIX_OFFSET, buf, len);
        }
index a5824990bd2a8c789e69d18bb2e3f12f26548248..56746539bea2c6da6da647fa414d2989abff894e 100644 (file)
@@ -39,9 +39,10 @@ enum ath10k_debug_mask {
 
 extern unsigned int ath10k_debug_mask;
 
-__printf(1, 2) int ath10k_info(const char *fmt, ...);
-__printf(1, 2) int ath10k_err(const char *fmt, ...);
-__printf(1, 2) int ath10k_warn(const char *fmt, ...);
+__printf(2, 3) int ath10k_info(struct ath10k *ar, const char *fmt, ...);
+__printf(2, 3) int ath10k_err(struct ath10k *ar, const char *fmt, ...);
+__printf(2, 3) int ath10k_warn(struct ath10k *ar, const char *fmt, ...);
+void ath10k_print_driver_info(struct ath10k *ar);
 
 #ifdef CONFIG_ATH10K_DEBUGFS
 int ath10k_debug_start(struct ath10k *ar);
@@ -53,6 +54,10 @@ void ath10k_debug_read_service_map(struct ath10k *ar,
                                   size_t map_size);
 void ath10k_debug_read_target_stats(struct ath10k *ar,
                                    struct wmi_stats_event *ev);
+struct ath10k_fw_crash_data *
+ath10k_debug_get_new_fw_crash_data(struct ath10k *ar);
+
+void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer, int len);
 
 #define ATH10K_DFS_STAT_INC(ar, c) (ar->debug.dfs_stats.c++)
 
@@ -86,25 +91,40 @@ static inline void ath10k_debug_read_target_stats(struct ath10k *ar,
 {
 }
 
+static inline void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer,
+                                          int len)
+{
+}
+
+static inline struct ath10k_fw_crash_data *
+ath10k_debug_get_new_fw_crash_data(struct ath10k *ar)
+{
+       return NULL;
+}
+
 #define ATH10K_DFS_STAT_INC(ar, c) do { } while (0)
 
 #endif /* CONFIG_ATH10K_DEBUGFS */
 
 #ifdef CONFIG_ATH10K_DEBUG
-__printf(2, 3) void ath10k_dbg(enum ath10k_debug_mask mask,
+__printf(3, 4) void ath10k_dbg(struct ath10k *ar,
+                              enum ath10k_debug_mask mask,
                               const char *fmt, ...);
-void ath10k_dbg_dump(enum ath10k_debug_mask mask,
+void ath10k_dbg_dump(struct ath10k *ar,
+                    enum ath10k_debug_mask mask,
                     const char *msg, const char *prefix,
                     const void *buf, size_t len);
 #else /* CONFIG_ATH10K_DEBUG */
 
-static inline int ath10k_dbg(enum ath10k_debug_mask dbg_mask,
+static inline int ath10k_dbg(struct ath10k *ar,
+                            enum ath10k_debug_mask dbg_mask,
                             const char *fmt, ...)
 {
        return 0;
 }
 
-static inline void ath10k_dbg_dump(enum ath10k_debug_mask mask,
+static inline void ath10k_dbg_dump(struct ath10k *ar,
+                                  enum ath10k_debug_mask mask,
                                   const char *msg, const char *prefix,
                                   const void *buf, size_t len)
 {
index 5fdc40d3b378303a77edb1b39fc46cb5c3660d0a..fd9a251f06596a646a07167477b2f85beb4269eb 100644 (file)
@@ -46,7 +46,7 @@ static struct sk_buff *ath10k_htc_build_tx_ctrl_skb(void *ar)
 
        skb = dev_alloc_skb(ATH10K_HTC_CONTROL_BUFFER_SIZE);
        if (!skb) {
-               ath10k_warn("Unable to allocate ctrl skb\n");
+               ath10k_warn(ar, "Unable to allocate ctrl skb\n");
                return NULL;
        }
 
@@ -56,7 +56,7 @@ static struct sk_buff *ath10k_htc_build_tx_ctrl_skb(void *ar)
        skb_cb = ATH10K_SKB_CB(skb);
        memset(skb_cb, 0, sizeof(*skb_cb));
 
-       ath10k_dbg(ATH10K_DBG_HTC, "%s: skb %p\n", __func__, skb);
+       ath10k_dbg(ar, ATH10K_DBG_HTC, "%s: skb %p\n", __func__, skb);
        return skb;
 }
 
@@ -72,13 +72,15 @@ static inline void ath10k_htc_restore_tx_skb(struct ath10k_htc *htc,
 static void ath10k_htc_notify_tx_completion(struct ath10k_htc_ep *ep,
                                            struct sk_buff *skb)
 {
-       ath10k_dbg(ATH10K_DBG_HTC, "%s: ep %d skb %p\n", __func__,
+       struct ath10k *ar = ep->htc->ar;
+
+       ath10k_dbg(ar, ATH10K_DBG_HTC, "%s: ep %d skb %p\n", __func__,
                   ep->eid, skb);
 
        ath10k_htc_restore_tx_skb(ep->htc, skb);
 
        if (!ep->ep_ops.ep_tx_complete) {
-               ath10k_warn("no tx handler for eid %d\n", ep->eid);
+               ath10k_warn(ar, "no tx handler for eid %d\n", ep->eid);
                dev_kfree_skb_any(skb);
                return;
        }
@@ -89,12 +91,14 @@ static void ath10k_htc_notify_tx_completion(struct ath10k_htc_ep *ep,
 /* assumes tx_lock is held */
 static bool ath10k_htc_ep_need_credit_update(struct ath10k_htc_ep *ep)
 {
+       struct ath10k *ar = ep->htc->ar;
+
        if (!ep->tx_credit_flow_enabled)
                return false;
        if (ep->tx_credits >= ep->tx_credits_per_max_message)
                return false;
 
-       ath10k_dbg(ATH10K_DBG_HTC, "HTC: endpoint %d needs credit update\n",
+       ath10k_dbg(ar, ATH10K_DBG_HTC, "HTC: endpoint %d needs credit update\n",
                   ep->eid);
        return true;
 }
@@ -123,6 +127,7 @@ int ath10k_htc_send(struct ath10k_htc *htc,
                    enum ath10k_htc_ep_id eid,
                    struct sk_buff *skb)
 {
+       struct ath10k *ar = htc->ar;
        struct ath10k_htc_ep *ep = &htc->endpoint[eid];
        struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb);
        struct ath10k_hif_sg_item sg_item;
@@ -134,18 +139,10 @@ int ath10k_htc_send(struct ath10k_htc *htc,
                return -ECOMM;
 
        if (eid >= ATH10K_HTC_EP_COUNT) {
-               ath10k_warn("Invalid endpoint id: %d\n", eid);
+               ath10k_warn(ar, "Invalid endpoint id: %d\n", eid);
                return -ENOENT;
        }
 
-       /* FIXME: This looks ugly, can we fix it? */
-       spin_lock_bh(&htc->tx_lock);
-       if (htc->stopped) {
-               spin_unlock_bh(&htc->tx_lock);
-               return -ESHUTDOWN;
-       }
-       spin_unlock_bh(&htc->tx_lock);
-
        skb_push(skb, sizeof(struct ath10k_htc_hdr));
 
        if (ep->tx_credit_flow_enabled) {
@@ -157,7 +154,7 @@ int ath10k_htc_send(struct ath10k_htc *htc,
                        goto err_pull;
                }
                ep->tx_credits -= credits;
-               ath10k_dbg(ATH10K_DBG_HTC,
+               ath10k_dbg(ar, ATH10K_DBG_HTC,
                           "htc ep %d consumed %d credits (total %d)\n",
                           eid, credits, ep->tx_credits);
                spin_unlock_bh(&htc->tx_lock);
@@ -188,7 +185,7 @@ err_credits:
        if (ep->tx_credit_flow_enabled) {
                spin_lock_bh(&htc->tx_lock);
                ep->tx_credits += credits;
-               ath10k_dbg(ATH10K_DBG_HTC,
+               ath10k_dbg(ar, ATH10K_DBG_HTC,
                           "htc ep %d reverted %d credits back (total %d)\n",
                           eid, credits, ep->tx_credits);
                spin_unlock_bh(&htc->tx_lock);
@@ -227,11 +224,12 @@ ath10k_htc_process_credit_report(struct ath10k_htc *htc,
                                 int len,
                                 enum ath10k_htc_ep_id eid)
 {
+       struct ath10k *ar = htc->ar;
        struct ath10k_htc_ep *ep;
        int i, n_reports;
 
        if (len % sizeof(*report))
-               ath10k_warn("Uneven credit report len %d", len);
+               ath10k_warn(ar, "Uneven credit report len %d", len);
 
        n_reports = len / sizeof(*report);
 
@@ -243,7 +241,7 @@ ath10k_htc_process_credit_report(struct ath10k_htc *htc,
                ep = &htc->endpoint[report->eid];
                ep->tx_credits += report->credits;
 
-               ath10k_dbg(ATH10K_DBG_HTC, "htc ep %d got %d credits (total %d)\n",
+               ath10k_dbg(ar, ATH10K_DBG_HTC, "htc ep %d got %d credits (total %d)\n",
                           report->eid, report->credits, ep->tx_credits);
 
                if (ep->ep_ops.ep_tx_credits) {
@@ -260,6 +258,7 @@ static int ath10k_htc_process_trailer(struct ath10k_htc *htc,
                                      int length,
                                      enum ath10k_htc_ep_id src_eid)
 {
+       struct ath10k *ar = htc->ar;
        int status = 0;
        struct ath10k_htc_record *record;
        u8 *orig_buffer;
@@ -279,7 +278,7 @@ static int ath10k_htc_process_trailer(struct ath10k_htc *htc,
 
                if (record->hdr.len > length) {
                        /* no room left in buffer for record */
-                       ath10k_warn("Invalid record length: %d\n",
+                       ath10k_warn(ar, "Invalid record length: %d\n",
                                    record->hdr.len);
                        status = -EINVAL;
                        break;
@@ -289,7 +288,7 @@ static int ath10k_htc_process_trailer(struct ath10k_htc *htc,
                case ATH10K_HTC_RECORD_CREDITS:
                        len = sizeof(struct ath10k_htc_credit_report);
                        if (record->hdr.len < len) {
-                               ath10k_warn("Credit report too long\n");
+                               ath10k_warn(ar, "Credit report too long\n");
                                status = -EINVAL;
                                break;
                        }
@@ -299,7 +298,7 @@ static int ath10k_htc_process_trailer(struct ath10k_htc *htc,
                                                         src_eid);
                        break;
                default:
-                       ath10k_warn("Unhandled record: id:%d length:%d\n",
+                       ath10k_warn(ar, "Unhandled record: id:%d length:%d\n",
                                    record->hdr.id, record->hdr.len);
                        break;
                }
@@ -313,7 +312,7 @@ static int ath10k_htc_process_trailer(struct ath10k_htc *htc,
        }
 
        if (status)
-               ath10k_dbg_dump(ATH10K_DBG_HTC, "htc rx bad trailer", "",
+               ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc rx bad trailer", "",
                                orig_buffer, orig_length);
 
        return status;
@@ -339,8 +338,8 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar,
        eid = hdr->eid;
 
        if (eid >= ATH10K_HTC_EP_COUNT) {
-               ath10k_warn("HTC Rx: invalid eid %d\n", eid);
-               ath10k_dbg_dump(ATH10K_DBG_HTC, "htc bad header", "",
+               ath10k_warn(ar, "HTC Rx: invalid eid %d\n", eid);
+               ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc bad header", "",
                                hdr, sizeof(*hdr));
                status = -EINVAL;
                goto out;
@@ -360,19 +359,19 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar,
        payload_len = __le16_to_cpu(hdr->len);
 
        if (payload_len + sizeof(*hdr) > ATH10K_HTC_MAX_LEN) {
-               ath10k_warn("HTC rx frame too long, len: %zu\n",
+               ath10k_warn(ar, "HTC rx frame too long, len: %zu\n",
                            payload_len + sizeof(*hdr));
-               ath10k_dbg_dump(ATH10K_DBG_HTC, "htc bad rx pkt len", "",
+               ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc bad rx pkt len", "",
                                hdr, sizeof(*hdr));
                status = -EINVAL;
                goto out;
        }
 
        if (skb->len < payload_len) {
-               ath10k_dbg(ATH10K_DBG_HTC,
+               ath10k_dbg(ar, ATH10K_DBG_HTC,
                           "HTC Rx: insufficient length, got %d, expected %d\n",
                           skb->len, payload_len);
-               ath10k_dbg_dump(ATH10K_DBG_HTC, "htc bad rx pkt len",
+               ath10k_dbg_dump(ar, ATH10K_DBG_HTC, "htc bad rx pkt len",
                                "", hdr, sizeof(*hdr));
                status = -EINVAL;
                goto out;
@@ -388,7 +387,7 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar,
 
                if ((trailer_len < min_len) ||
                    (trailer_len > payload_len)) {
-                       ath10k_warn("Invalid trailer length: %d\n",
+                       ath10k_warn(ar, "Invalid trailer length: %d\n",
                                    trailer_len);
                        status = -EPROTO;
                        goto out;
@@ -421,7 +420,7 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar,
                                 * this is a fatal error, target should not be
                                 * sending unsolicited messages on the ep 0
                                 */
-                               ath10k_warn("HTC rx ctrl still processing\n");
+                               ath10k_warn(ar, "HTC rx ctrl still processing\n");
                                status = -EINVAL;
                                complete(&htc->ctl_resp);
                                goto out;
@@ -442,7 +441,7 @@ static int ath10k_htc_rx_completion_handler(struct ath10k *ar,
                goto out;
        }
 
-       ath10k_dbg(ATH10K_DBG_HTC, "htc rx completion ep %d skb %p\n",
+       ath10k_dbg(ar, ATH10K_DBG_HTC, "htc rx completion ep %d skb %p\n",
                   eid, skb);
        ep->ep_ops.ep_rx_complete(ar, skb);
 
@@ -459,7 +458,7 @@ static void ath10k_htc_control_rx_complete(struct ath10k *ar,
 {
        /* This is unexpected. FW is not supposed to send regular rx on this
         * endpoint. */
-       ath10k_warn("unexpected htc rx\n");
+       ath10k_warn(ar, "unexpected htc rx\n");
        kfree_skb(skb);
 }
 
@@ -546,6 +545,7 @@ static u8 ath10k_htc_get_credit_allocation(struct ath10k_htc *htc,
 
 int ath10k_htc_wait_target(struct ath10k_htc *htc)
 {
+       struct ath10k *ar = htc->ar;
        int i, status = 0;
        struct ath10k_htc_svc_conn_req conn_req;
        struct ath10k_htc_svc_conn_resp conn_resp;
@@ -563,7 +563,7 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)
                 * iomap writes unmasking PCI CE irqs aren't propagated
                 * properly in KVM PCI-passthrough sometimes.
                 */
-               ath10k_warn("failed to receive control response completion, polling..\n");
+               ath10k_warn(ar, "failed to receive control response completion, polling..\n");
 
                for (i = 0; i < CE_COUNT; i++)
                        ath10k_hif_send_complete_check(htc->ar, i, 1);
@@ -576,12 +576,12 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)
        }
 
        if (status < 0) {
-               ath10k_err("ctl_resp never came in (%d)\n", status);
+               ath10k_err(ar, "ctl_resp never came in (%d)\n", status);
                return status;
        }
 
        if (htc->control_resp_len < sizeof(msg->hdr) + sizeof(msg->ready)) {
-               ath10k_err("Invalid HTC ready msg len:%d\n",
+               ath10k_err(ar, "Invalid HTC ready msg len:%d\n",
                           htc->control_resp_len);
                return -ECOMM;
        }
@@ -592,21 +592,21 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)
        credit_size  = __le16_to_cpu(msg->ready.credit_size);
 
        if (message_id != ATH10K_HTC_MSG_READY_ID) {
-               ath10k_err("Invalid HTC ready msg: 0x%x\n", message_id);
+               ath10k_err(ar, "Invalid HTC ready msg: 0x%x\n", message_id);
                return -ECOMM;
        }
 
        htc->total_transmit_credits = credit_count;
        htc->target_credit_size = credit_size;
 
-       ath10k_dbg(ATH10K_DBG_HTC,
+       ath10k_dbg(ar, ATH10K_DBG_HTC,
                   "Target ready! transmit resources: %d size:%d\n",
                   htc->total_transmit_credits,
                   htc->target_credit_size);
 
        if ((htc->total_transmit_credits == 0) ||
            (htc->target_credit_size == 0)) {
-               ath10k_err("Invalid credit size received\n");
+               ath10k_err(ar, "Invalid credit size received\n");
                return -ECOMM;
        }
 
@@ -623,7 +623,8 @@ int ath10k_htc_wait_target(struct ath10k_htc *htc)
        /* connect fake service */
        status = ath10k_htc_connect_service(htc, &conn_req, &conn_resp);
        if (status) {
-               ath10k_err("could not connect to htc service (%d)\n", status);
+               ath10k_err(ar, "could not connect to htc service (%d)\n",
+                          status);
                return status;
        }
 
@@ -634,6 +635,7 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,
                               struct ath10k_htc_svc_conn_req *conn_req,
                               struct ath10k_htc_svc_conn_resp *conn_resp)
 {
+       struct ath10k *ar = htc->ar;
        struct ath10k_htc_msg *msg;
        struct ath10k_htc_conn_svc *req_msg;
        struct ath10k_htc_conn_svc_response resp_msg_dummy;
@@ -659,13 +661,13 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,
        tx_alloc = ath10k_htc_get_credit_allocation(htc,
                                                    conn_req->service_id);
        if (!tx_alloc)
-               ath10k_dbg(ATH10K_DBG_BOOT,
+               ath10k_dbg(ar, ATH10K_DBG_BOOT,
                           "boot htc service %s does not allocate target credits\n",
                           htc_service_name(conn_req->service_id));
 
        skb = ath10k_htc_build_tx_ctrl_skb(htc->ar);
        if (!skb) {
-               ath10k_err("Failed to allocate HTC packet\n");
+               ath10k_err(ar, "Failed to allocate HTC packet\n");
                return -ENOMEM;
        }
 
@@ -703,7 +705,7 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,
        if (status <= 0) {
                if (status == 0)
                        status = -ETIMEDOUT;
-               ath10k_err("Service connect timeout: %d\n", status);
+               ath10k_err(ar, "Service connect timeout: %d\n", status);
                return status;
        }
 
@@ -716,11 +718,11 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,
        if ((message_id != ATH10K_HTC_MSG_CONNECT_SERVICE_RESP_ID) ||
            (htc->control_resp_len < sizeof(msg->hdr) +
             sizeof(msg->connect_service_response))) {
-               ath10k_err("Invalid resp message ID 0x%x", message_id);
+               ath10k_err(ar, "Invalid resp message ID 0x%x", message_id);
                return -EPROTO;
        }
 
-       ath10k_dbg(ATH10K_DBG_HTC,
+       ath10k_dbg(ar, ATH10K_DBG_HTC,
                   "HTC Service %s connect response: status: 0x%x, assigned ep: 0x%x\n",
                   htc_service_name(service_id),
                   resp_msg->status, resp_msg->eid);
@@ -729,7 +731,7 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,
 
        /* check response status */
        if (resp_msg->status != ATH10K_HTC_CONN_SVC_STATUS_SUCCESS) {
-               ath10k_err("HTC Service %s connect request failed: 0x%x)\n",
+               ath10k_err(ar, "HTC Service %s connect request failed: 0x%x)\n",
                           htc_service_name(service_id),
                           resp_msg->status);
                return -EPROTO;
@@ -780,18 +782,18 @@ setup:
        if (status)
                return status;
 
-       ath10k_dbg(ATH10K_DBG_BOOT,
+       ath10k_dbg(ar, ATH10K_DBG_BOOT,
                   "boot htc service '%s' ul pipe %d dl pipe %d eid %d ready\n",
                   htc_service_name(ep->service_id), ep->ul_pipe_id,
                   ep->dl_pipe_id, ep->eid);
 
-       ath10k_dbg(ATH10K_DBG_BOOT,
+       ath10k_dbg(ar, ATH10K_DBG_BOOT,
                   "boot htc ep %d ul polled %d dl polled %d\n",
                   ep->eid, ep->ul_is_polled, ep->dl_is_polled);
 
        if (disable_credit_flow_ctrl && ep->tx_credit_flow_enabled) {
                ep->tx_credit_flow_enabled = false;
-               ath10k_dbg(ATH10K_DBG_BOOT,
+               ath10k_dbg(ar, ATH10K_DBG_BOOT,
                           "boot htc service '%s' eid %d TX flow control disabled\n",
                           htc_service_name(ep->service_id), assigned_eid);
        }
@@ -799,13 +801,13 @@ setup:
        return status;
 }
 
-struct sk_buff *ath10k_htc_alloc_skb(int size)
+struct sk_buff *ath10k_htc_alloc_skb(struct ath10k *ar, int size)
 {
        struct sk_buff *skb;
 
        skb = dev_alloc_skb(size + sizeof(struct ath10k_htc_hdr));
        if (!skb) {
-               ath10k_warn("could not allocate HTC tx skb\n");
+               ath10k_warn(ar, "could not allocate HTC tx skb\n");
                return NULL;
        }
 
@@ -813,13 +815,14 @@ struct sk_buff *ath10k_htc_alloc_skb(int size)
 
        /* FW/HTC requires 4-byte aligned streams */
        if (!IS_ALIGNED((unsigned long)skb->data, 4))
-               ath10k_warn("Unaligned HTC tx skb\n");
+               ath10k_warn(ar, "Unaligned HTC tx skb\n");
 
        return skb;
 }
 
 int ath10k_htc_start(struct ath10k_htc *htc)
 {
+       struct ath10k *ar = htc->ar;
        struct sk_buff *skb;
        int status = 0;
        struct ath10k_htc_msg *msg;
@@ -835,7 +838,7 @@ int ath10k_htc_start(struct ath10k_htc *htc)
        msg->hdr.message_id =
                __cpu_to_le16(ATH10K_HTC_MSG_SETUP_COMPLETE_EX_ID);
 
-       ath10k_dbg(ATH10K_DBG_HTC, "HTC is using TX credit flow control\n");
+       ath10k_dbg(ar, ATH10K_DBG_HTC, "HTC is using TX credit flow control\n");
 
        status = ath10k_htc_send(htc, ATH10K_HTC_EP_0, skb);
        if (status) {
@@ -846,13 +849,6 @@ int ath10k_htc_start(struct ath10k_htc *htc)
        return 0;
 }
 
-void ath10k_htc_stop(struct ath10k_htc *htc)
-{
-       spin_lock_bh(&htc->tx_lock);
-       htc->stopped = true;
-       spin_unlock_bh(&htc->tx_lock);
-}
-
 /* registered target arrival callback from the HIF layer */
 int ath10k_htc_init(struct ath10k *ar)
 {
@@ -862,7 +858,6 @@ int ath10k_htc_init(struct ath10k *ar)
 
        spin_lock_init(&htc->tx_lock);
 
-       htc->stopped = false;
        ath10k_htc_reset_endpoint_states(htc);
 
        /* setup HIF layer callbacks */
index 4716d331e6b6504d712c858345545a410cbcbab1..bf532f6711892e9b1dee4a1f971fe8d251832561 100644 (file)
@@ -332,7 +332,7 @@ struct ath10k_htc {
        struct ath10k *ar;
        struct ath10k_htc_ep endpoint[ATH10K_HTC_EP_COUNT];
 
-       /* protects endpoint and stopped fields */
+       /* protects endpoints */
        spinlock_t tx_lock;
 
        struct ath10k_htc_ops htc_ops;
@@ -345,8 +345,6 @@ struct ath10k_htc {
        int total_transmit_credits;
        struct ath10k_htc_svc_tx_credits service_tx_alloc[ATH10K_HTC_EP_COUNT];
        int target_credit_size;
-
-       bool stopped;
 };
 
 int ath10k_htc_init(struct ath10k *ar);
@@ -357,7 +355,6 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,
                               struct ath10k_htc_svc_conn_resp *conn_resp);
 int ath10k_htc_send(struct ath10k_htc *htc, enum ath10k_htc_ep_id eid,
                    struct sk_buff *packet);
-void ath10k_htc_stop(struct ath10k_htc *htc);
-struct sk_buff *ath10k_htc_alloc_skb(int size);
+struct sk_buff *ath10k_htc_alloc_skb(struct ath10k *ar, int size);
 
 #endif
index 19c12cc8d66317ebbb8123b4a54b6654c5705c26..87daae11f1160ba8d181dd7fa56924f2f3cb3306 100644 (file)
@@ -74,12 +74,14 @@ int ath10k_htt_init(struct ath10k *ar)
 
 static int ath10k_htt_verify_version(struct ath10k_htt *htt)
 {
-       ath10k_dbg(ATH10K_DBG_BOOT, "htt target version %d.%d\n",
+       struct ath10k *ar = htt->ar;
+
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "htt target version %d.%d\n",
                   htt->target_version_major, htt->target_version_minor);
 
        if (htt->target_version_major != 2 &&
            htt->target_version_major != 3) {
-               ath10k_err("unsupported htt major version %d. supported versions are 2 and 3\n",
+               ath10k_err(ar, "unsupported htt major version %d. supported versions are 2 and 3\n",
                           htt->target_version_major);
                return -ENOTSUPP;
        }
@@ -89,6 +91,7 @@ static int ath10k_htt_verify_version(struct ath10k_htt *htt)
 
 int ath10k_htt_setup(struct ath10k_htt *htt)
 {
+       struct ath10k *ar = htt->ar;
        int status;
 
        init_completion(&htt->target_version_received);
@@ -100,7 +103,7 @@ int ath10k_htt_setup(struct ath10k_htt *htt)
        status = wait_for_completion_timeout(&htt->target_version_received,
                                                HTT_TARGET_VERSION_TIMEOUT_HZ);
        if (status <= 0) {
-               ath10k_warn("htt version request timed out\n");
+               ath10k_warn(ar, "htt version request timed out\n");
                return -ETIMEDOUT;
        }
 
index 80cdac15588a2352608881acb5fc59fe8808f0ec..30927b1d71098519f04b80d5cbcff4d607a85a40 100644 (file)
@@ -271,13 +271,14 @@ void ath10k_htt_rx_free(struct ath10k_htt *htt)
 
 static inline struct sk_buff *ath10k_htt_rx_netbuf_pop(struct ath10k_htt *htt)
 {
+       struct ath10k *ar = htt->ar;
        int idx;
        struct sk_buff *msdu;
 
        lockdep_assert_held(&htt->rx_ring.lock);
 
        if (htt->rx_ring.fill_cnt == 0) {
-               ath10k_warn("tried to pop sk_buff from an empty rx ring\n");
+               ath10k_warn(ar, "tried to pop sk_buff from an empty rx ring\n");
                return NULL;
        }
 
@@ -311,6 +312,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
                                   struct sk_buff **tail_msdu,
                                   u32 *attention)
 {
+       struct ath10k *ar = htt->ar;
        int msdu_len, msdu_chaining = 0;
        struct sk_buff *msdu;
        struct htt_rx_desc *rx_desc;
@@ -318,7 +320,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
        lockdep_assert_held(&htt->rx_ring.lock);
 
        if (htt->rx_confused) {
-               ath10k_warn("htt is confused. refusing rx\n");
+               ath10k_warn(ar, "htt is confused. refusing rx\n");
                return -1;
        }
 
@@ -331,7 +333,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
                                 msdu->len + skb_tailroom(msdu),
                                 DMA_FROM_DEVICE);
 
-               ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx pop: ",
+               ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx pop: ",
                                msdu->data, msdu->len + skb_tailroom(msdu));
 
                rx_desc = (struct htt_rx_desc *)msdu->data;
@@ -354,7 +356,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
                        ath10k_htt_rx_free_msdu_chain(*head_msdu);
                        *head_msdu = NULL;
                        msdu = NULL;
-                       ath10k_err("htt rx stopped. cannot recover\n");
+                       ath10k_err(ar, "htt rx stopped. cannot recover\n");
                        htt->rx_confused = true;
                        break;
                }
@@ -429,7 +431,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
                                         next->len + skb_tailroom(next),
                                         DMA_FROM_DEVICE);
 
-                       ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL,
+                       ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL,
                                        "htt rx chained: ", next->data,
                                        next->len + skb_tailroom(next));
 
@@ -483,13 +485,14 @@ static void ath10k_htt_rx_replenish_task(unsigned long ptr)
 
 int ath10k_htt_rx_alloc(struct ath10k_htt *htt)
 {
+       struct ath10k *ar = htt->ar;
        dma_addr_t paddr;
        void *vaddr;
        struct timer_list *timer = &htt->rx_ring.refill_retry_timer;
 
        htt->rx_ring.size = ath10k_htt_rx_ring_size(htt);
        if (!is_power_of_2(htt->rx_ring.size)) {
-               ath10k_warn("htt rx ring size is not power of 2\n");
+               ath10k_warn(ar, "htt rx ring size is not power of 2\n");
                return -EINVAL;
        }
 
@@ -550,7 +553,7 @@ int ath10k_htt_rx_alloc(struct ath10k_htt *htt)
        tasklet_init(&htt->txrx_compl_task, ath10k_htt_txrx_compl_task,
                     (unsigned long)htt);
 
-       ath10k_dbg(ATH10K_DBG_BOOT, "htt rx ring size %d fill_level %d\n",
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "htt rx ring size %d fill_level %d\n",
                   htt->rx_ring.size, htt->rx_ring.fill_level);
        return 0;
 
@@ -572,7 +575,8 @@ err_netbuf:
        return -ENOMEM;
 }
 
-static int ath10k_htt_rx_crypto_param_len(enum htt_rx_mpdu_encrypt_type type)
+static int ath10k_htt_rx_crypto_param_len(struct ath10k *ar,
+                                         enum htt_rx_mpdu_encrypt_type type)
 {
        switch (type) {
        case HTT_RX_MPDU_ENCRYPT_WEP40:
@@ -588,11 +592,12 @@ static int ath10k_htt_rx_crypto_param_len(enum htt_rx_mpdu_encrypt_type type)
                return 0;
        }
 
-       ath10k_warn("unknown encryption type %d\n", type);
+       ath10k_warn(ar, "unknown encryption type %d\n", type);
        return 0;
 }
 
-static int ath10k_htt_rx_crypto_tail_len(enum htt_rx_mpdu_encrypt_type type)
+static int ath10k_htt_rx_crypto_tail_len(struct ath10k *ar,
+                                        enum htt_rx_mpdu_encrypt_type type)
 {
        switch (type) {
        case HTT_RX_MPDU_ENCRYPT_NONE:
@@ -608,7 +613,7 @@ static int ath10k_htt_rx_crypto_tail_len(enum htt_rx_mpdu_encrypt_type type)
                return 8;
        }
 
-       ath10k_warn("unknown encryption type %d\n", type);
+       ath10k_warn(ar, "unknown encryption type %d\n", type);
        return 0;
 }
 
@@ -819,19 +824,55 @@ static bool ath10k_htt_rx_h_channel(struct ath10k *ar,
        return true;
 }
 
+static const char * const tid_to_ac[] = {
+       "BE",
+       "BK",
+       "BK",
+       "BE",
+       "VI",
+       "VI",
+       "VO",
+       "VO",
+};
+
+static char *ath10k_get_tid(struct ieee80211_hdr *hdr, char *out, size_t size)
+{
+       u8 *qc;
+       int tid;
+
+       if (!ieee80211_is_data_qos(hdr->frame_control))
+               return "";
+
+       qc = ieee80211_get_qos_ctl(hdr);
+       tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
+       if (tid < 8)
+               snprintf(out, size, "tid %d (%s)", tid, tid_to_ac[tid]);
+       else
+               snprintf(out, size, "tid %d", tid);
+
+       return out;
+}
+
 static void ath10k_process_rx(struct ath10k *ar,
                              struct ieee80211_rx_status *rx_status,
                              struct sk_buff *skb)
 {
        struct ieee80211_rx_status *status;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       char tid[32];
 
        status = IEEE80211_SKB_RXCB(skb);
        *status = *rx_status;
 
-       ath10k_dbg(ATH10K_DBG_DATA,
-                  "rx skb %p len %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %imic-err %i\n",
+       ath10k_dbg(ar, ATH10K_DBG_DATA,
+                  "rx skb %p len %u peer %pM %s %s sn %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n",
                   skb,
                   skb->len,
+                  ieee80211_get_SA(hdr),
+                  ath10k_get_tid(hdr, tid, sizeof(tid)),
+                  is_multicast_ether_addr(ieee80211_get_DA(hdr)) ?
+                                                       "mcast" : "ucast",
+                  (__le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4,
                   status->flag == 0 ? "legacy" : "",
                   status->flag & RX_FLAG_HT ? "ht" : "",
                   status->flag & RX_FLAG_VHT ? "vht" : "",
@@ -843,8 +884,9 @@ static void ath10k_process_rx(struct ath10k *ar,
                   status->freq,
                   status->band, status->flag,
                   !!(status->flag & RX_FLAG_FAILED_FCS_CRC),
-                  !!(status->flag & RX_FLAG_MMIC_ERROR));
-       ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "rx skb: ",
+                  !!(status->flag & RX_FLAG_MMIC_ERROR),
+                  !!(status->flag & RX_FLAG_AMSDU_MORE));
+       ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "rx skb: ",
                        skb->data, skb->len);
 
        ieee80211_rx(ar->hw, skb);
@@ -860,13 +902,14 @@ static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt,
                                struct ieee80211_rx_status *rx_status,
                                struct sk_buff *skb_in)
 {
+       struct ath10k *ar = htt->ar;
        struct htt_rx_desc *rxd;
        struct sk_buff *skb = skb_in;
        struct sk_buff *first;
        enum rx_msdu_decap_format fmt;
        enum htt_rx_mpdu_encrypt_type enctype;
        struct ieee80211_hdr *hdr;
-       u8 hdr_buf[64], addr[ETH_ALEN], *qos;
+       u8 hdr_buf[64], da[ETH_ALEN], sa[ETH_ALEN], *qos;
        unsigned int hdr_len;
 
        rxd = (void *)skb->data - sizeof(*rxd);
@@ -893,8 +936,8 @@ static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt,
                /* First frame in an A-MSDU chain has more decapped data. */
                if (skb == first) {
                        len = round_up(ieee80211_hdrlen(hdr->frame_control), 4);
-                       len += round_up(ath10k_htt_rx_crypto_param_len(enctype),
-                                       4);
+                       len += round_up(ath10k_htt_rx_crypto_param_len(ar,
+                                               enctype), 4);
                        decap_hdr += len;
                }
 
@@ -904,10 +947,11 @@ static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt,
                        skb_trim(skb, skb->len - FCS_LEN);
                        break;
                case RX_MSDU_DECAP_NATIVE_WIFI:
-                       /* pull decapped header and copy DA */
+                       /* pull decapped header and copy SA & DA */
                        hdr = (struct ieee80211_hdr *)skb->data;
                        hdr_len = ath10k_htt_rx_nwifi_hdrlen(hdr);
-                       memcpy(addr, ieee80211_get_DA(hdr), ETH_ALEN);
+                       memcpy(da, ieee80211_get_DA(hdr), ETH_ALEN);
+                       memcpy(sa, ieee80211_get_SA(hdr), ETH_ALEN);
                        skb_pull(skb, hdr_len);
 
                        /* push original 802.11 header */
@@ -921,8 +965,11 @@ static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt,
                        qos = ieee80211_get_qos_ctl(hdr);
                        qos[0] &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
 
-                       /* original 802.11 header has a different DA */
-                       memcpy(ieee80211_get_DA(hdr), addr, ETH_ALEN);
+                       /* original 802.11 header has a different DA and in
+                        * case of 4addr it may also have different SA
+                        */
+                       memcpy(ieee80211_get_DA(hdr), da, ETH_ALEN);
+                       memcpy(ieee80211_get_SA(hdr), sa, ETH_ALEN);
                        break;
                case RX_MSDU_DECAP_ETHERNET2_DIX:
                        /* strip ethernet header and insert decapped 802.11
@@ -965,6 +1012,7 @@ static void ath10k_htt_rx_msdu(struct ath10k_htt *htt,
                               struct ieee80211_rx_status *rx_status,
                               struct sk_buff *skb)
 {
+       struct ath10k *ar = htt->ar;
        struct htt_rx_desc *rxd;
        struct ieee80211_hdr *hdr;
        enum rx_msdu_decap_format fmt;
@@ -974,7 +1022,7 @@ static void ath10k_htt_rx_msdu(struct ath10k_htt *htt,
 
        /* This shouldn't happen. If it does than it may be a FW bug. */
        if (skb->next) {
-               ath10k_warn("htt rx received chained non A-MSDU frame\n");
+               ath10k_warn(ar, "htt rx received chained non A-MSDU frame\n");
                ath10k_htt_rx_free_msdu_chain(skb->next);
                skb->next = NULL;
        }
@@ -1011,7 +1059,8 @@ static void ath10k_htt_rx_msdu(struct ath10k_htt *htt,
 
                rfc1042 = hdr;
                rfc1042 += roundup(hdr_len, 4);
-               rfc1042 += roundup(ath10k_htt_rx_crypto_param_len(enctype), 4);
+               rfc1042 += roundup(ath10k_htt_rx_crypto_param_len(ar,
+                                       enctype), 4);
 
                skb_pull(skb, sizeof(struct ethhdr));
                memcpy(skb_push(skb, sizeof(struct rfc1042_hdr)),
@@ -1120,27 +1169,29 @@ static bool ath10k_htt_rx_amsdu_allowed(struct ath10k_htt *htt,
                                        bool channel_set,
                                        u32 attention)
 {
+       struct ath10k *ar = htt->ar;
+
        if (head->len == 0) {
-               ath10k_dbg(ATH10K_DBG_HTT,
+               ath10k_dbg(ar, ATH10K_DBG_HTT,
                           "htt rx dropping due to zero-len\n");
                return false;
        }
 
        if (attention & RX_ATTENTION_FLAGS_DECRYPT_ERR) {
-               ath10k_dbg(ATH10K_DBG_HTT,
+               ath10k_dbg(ar, ATH10K_DBG_HTT,
                           "htt rx dropping due to decrypt-err\n");
                return false;
        }
 
        if (!channel_set) {
-               ath10k_warn("no channel configured; ignoring frame!\n");
+               ath10k_warn(ar, "no channel configured; ignoring frame!\n");
                return false;
        }
 
        /* Skip mgmt frames while we handle this in WMI */
        if (status == HTT_RX_IND_MPDU_STATUS_MGMT_CTRL ||
            attention & RX_ATTENTION_FLAGS_MGMT_TYPE) {
-               ath10k_dbg(ATH10K_DBG_HTT, "htt rx mgmt ctrl\n");
+               ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx mgmt ctrl\n");
                return false;
        }
 
@@ -1148,14 +1199,14 @@ static bool ath10k_htt_rx_amsdu_allowed(struct ath10k_htt *htt,
            status != HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR &&
            status != HTT_RX_IND_MPDU_STATUS_ERR_INV_PEER &&
            !htt->ar->monitor_started) {
-               ath10k_dbg(ATH10K_DBG_HTT,
+               ath10k_dbg(ar, ATH10K_DBG_HTT,
                           "htt rx ignoring frame w/ status %d\n",
                           status);
                return false;
        }
 
        if (test_bit(ATH10K_CAC_RUNNING, &htt->ar->dev_flags)) {
-               ath10k_dbg(ATH10K_DBG_HTT,
+               ath10k_dbg(ar, ATH10K_DBG_HTT,
                           "htt rx CAC running\n");
                return false;
        }
@@ -1166,6 +1217,7 @@ static bool ath10k_htt_rx_amsdu_allowed(struct ath10k_htt *htt,
 static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
                                  struct htt_rx_indication *rx)
 {
+       struct ath10k *ar = htt->ar;
        struct ieee80211_rx_status *rx_status = &htt->rx_status;
        struct htt_rx_indication_mpdu_range *mpdu_ranges;
        struct htt_rx_desc *rxd;
@@ -1211,7 +1263,7 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
                                      rx_status);
        }
 
-       ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx ind: ",
+       ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx ind: ",
                        rx, sizeof(*rx) +
                        (sizeof(struct htt_rx_indication_mpdu_range) *
                                num_mpdu_ranges));
@@ -1233,7 +1285,7 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
                                                      &attention);
 
                        if (ret < 0) {
-                               ath10k_warn("failed to pop amsdu from htt rx ring %d\n",
+                               ath10k_warn(ar, "failed to pop amsdu from htt rx ring %d\n",
                                            ret);
                                ath10k_htt_rx_free_msdu_chain(msdu_head);
                                continue;
@@ -1282,6 +1334,7 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
 static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
                                struct htt_rx_fragment_indication *frag)
 {
+       struct ath10k *ar = htt->ar;
        struct sk_buff *msdu_head, *msdu_tail;
        enum htt_rx_mpdu_encrypt_type enctype;
        struct htt_rx_desc *rxd;
@@ -1308,10 +1361,10 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
                                      &attention);
        spin_unlock_bh(&htt->rx_ring.lock);
 
-       ath10k_dbg(ATH10K_DBG_HTT_DUMP, "htt rx frag ahead\n");
+       ath10k_dbg(ar, ATH10K_DBG_HTT_DUMP, "htt rx frag ahead\n");
 
        if (ret) {
-               ath10k_warn("failed to pop amsdu from httr rx ring for fragmented rx %d\n",
+               ath10k_warn(ar, "failed to pop amsdu from httr rx ring for fragmented rx %d\n",
                            ret);
                ath10k_htt_rx_free_msdu_chain(msdu_head);
                return;
@@ -1328,7 +1381,7 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
                        RX_MSDU_START_INFO1_DECAP_FORMAT);
 
        if (fmt != RX_MSDU_DECAP_RAW) {
-               ath10k_warn("we dont support non-raw fragmented rx yet\n");
+               ath10k_warn(ar, "we dont support non-raw fragmented rx yet\n");
                dev_kfree_skb_any(msdu_head);
                goto end;
        }
@@ -1340,17 +1393,17 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
        msdu_head->ip_summed = ath10k_htt_rx_get_csum_state(msdu_head);
 
        if (tkip_mic_err)
-               ath10k_warn("tkip mic error\n");
+               ath10k_warn(ar, "tkip mic error\n");
 
        if (decrypt_err) {
-               ath10k_warn("decryption err in fragmented rx\n");
+               ath10k_warn(ar, "decryption err in fragmented rx\n");
                dev_kfree_skb_any(msdu_head);
                goto end;
        }
 
        if (enctype != HTT_RX_MPDU_ENCRYPT_NONE) {
                hdrlen = ieee80211_hdrlen(hdr->frame_control);
-               paramlen = ath10k_htt_rx_crypto_param_len(enctype);
+               paramlen = ath10k_htt_rx_crypto_param_len(ar, enctype);
 
                /* It is more efficient to move the header than the payload */
                memmove((void *)msdu_head->data + paramlen,
@@ -1364,7 +1417,7 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
        trim  = 4;
 
        /* remove crypto trailer */
-       trim += ath10k_htt_rx_crypto_tail_len(enctype);
+       trim += ath10k_htt_rx_crypto_tail_len(ar, enctype);
 
        /* last fragment of TKIP frags has MIC */
        if (!ieee80211_has_morefrags(hdr->frame_control) &&
@@ -1372,20 +1425,20 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
                trim += 8;
 
        if (trim > msdu_head->len) {
-               ath10k_warn("htt rx fragment: trailer longer than the frame itself? drop\n");
+               ath10k_warn(ar, "htt rx fragment: trailer longer than the frame itself? drop\n");
                dev_kfree_skb_any(msdu_head);
                goto end;
        }
 
        skb_trim(msdu_head, msdu_head->len - trim);
 
-       ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt rx frag mpdu: ",
+       ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx frag mpdu: ",
                        msdu_head->data, msdu_head->len);
        ath10k_process_rx(htt->ar, rx_status, msdu_head);
 
 end:
        if (fw_desc_len > 0) {
-               ath10k_dbg(ATH10K_DBG_HTT,
+               ath10k_dbg(ar, ATH10K_DBG_HTT,
                           "expecting more fragmented rx in one indication %d\n",
                           fw_desc_len);
        }
@@ -1415,12 +1468,12 @@ static void ath10k_htt_rx_frm_tx_compl(struct ath10k *ar,
                tx_done.discard = true;
                break;
        default:
-               ath10k_warn("unhandled tx completion status %d\n", status);
+               ath10k_warn(ar, "unhandled tx completion status %d\n", status);
                tx_done.discard = true;
                break;
        }
 
-       ath10k_dbg(ATH10K_DBG_HTT, "htt tx completion num_msdus %d\n",
+       ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx completion num_msdus %d\n",
                   resp->data_tx_completion.num_msdus);
 
        for (i = 0; i < resp->data_tx_completion.num_msdus; i++) {
@@ -1441,14 +1494,14 @@ static void ath10k_htt_rx_addba(struct ath10k *ar, struct htt_resp *resp)
        tid = MS(info0, HTT_RX_BA_INFO0_TID);
        peer_id = MS(info0, HTT_RX_BA_INFO0_PEER_ID);
 
-       ath10k_dbg(ATH10K_DBG_HTT,
+       ath10k_dbg(ar, ATH10K_DBG_HTT,
                   "htt rx addba tid %hu peer_id %hu size %hhu\n",
                   tid, peer_id, ev->window_size);
 
        spin_lock_bh(&ar->data_lock);
        peer = ath10k_peer_find_by_id(ar, peer_id);
        if (!peer) {
-               ath10k_warn("received addba event for invalid peer_id: %hu\n",
+               ath10k_warn(ar, "received addba event for invalid peer_id: %hu\n",
                            peer_id);
                spin_unlock_bh(&ar->data_lock);
                return;
@@ -1456,13 +1509,13 @@ static void ath10k_htt_rx_addba(struct ath10k *ar, struct htt_resp *resp)
 
        arvif = ath10k_get_arvif(ar, peer->vdev_id);
        if (!arvif) {
-               ath10k_warn("received addba event for invalid vdev_id: %u\n",
+               ath10k_warn(ar, "received addba event for invalid vdev_id: %u\n",
                            peer->vdev_id);
                spin_unlock_bh(&ar->data_lock);
                return;
        }
 
-       ath10k_dbg(ATH10K_DBG_HTT,
+       ath10k_dbg(ar, ATH10K_DBG_HTT,
                   "htt rx start rx ba session sta %pM tid %hu size %hhu\n",
                   peer->addr, tid, ev->window_size);
 
@@ -1481,14 +1534,14 @@ static void ath10k_htt_rx_delba(struct ath10k *ar, struct htt_resp *resp)
        tid = MS(info0, HTT_RX_BA_INFO0_TID);
        peer_id = MS(info0, HTT_RX_BA_INFO0_PEER_ID);
 
-       ath10k_dbg(ATH10K_DBG_HTT,
+       ath10k_dbg(ar, ATH10K_DBG_HTT,
                   "htt rx delba tid %hu peer_id %hu\n",
                   tid, peer_id);
 
        spin_lock_bh(&ar->data_lock);
        peer = ath10k_peer_find_by_id(ar, peer_id);
        if (!peer) {
-               ath10k_warn("received addba event for invalid peer_id: %hu\n",
+               ath10k_warn(ar, "received addba event for invalid peer_id: %hu\n",
                            peer_id);
                spin_unlock_bh(&ar->data_lock);
                return;
@@ -1496,13 +1549,13 @@ static void ath10k_htt_rx_delba(struct ath10k *ar, struct htt_resp *resp)
 
        arvif = ath10k_get_arvif(ar, peer->vdev_id);
        if (!arvif) {
-               ath10k_warn("received addba event for invalid vdev_id: %u\n",
+               ath10k_warn(ar, "received addba event for invalid vdev_id: %u\n",
                            peer->vdev_id);
                spin_unlock_bh(&ar->data_lock);
                return;
        }
 
-       ath10k_dbg(ATH10K_DBG_HTT,
+       ath10k_dbg(ar, ATH10K_DBG_HTT,
                   "htt rx stop rx ba session sta %pM tid %hu\n",
                   peer->addr, tid);
 
@@ -1517,9 +1570,9 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
 
        /* confirm alignment */
        if (!IS_ALIGNED((unsigned long)skb->data, 4))
-               ath10k_warn("unaligned htt message, expect trouble\n");
+               ath10k_warn(ar, "unaligned htt message, expect trouble\n");
 
-       ath10k_dbg(ATH10K_DBG_HTT, "htt rx, msg_type: 0x%0X\n",
+       ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx, msg_type: 0x%0X\n",
                   resp->hdr.msg_type);
        switch (resp->hdr.msg_type) {
        case HTT_T2H_MSG_TYPE_VERSION_CONF: {
@@ -1583,7 +1636,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
                struct ath10k *ar = htt->ar;
                struct htt_security_indication *ev = &resp->security_indication;
 
-               ath10k_dbg(ATH10K_DBG_HTT,
+               ath10k_dbg(ar, ATH10K_DBG_HTT,
                           "sec ind peer_id %d unicast %d type %d\n",
                          __le16_to_cpu(ev->peer_id),
                          !!(ev->flags & HTT_SECURITY_IS_UNICAST),
@@ -1592,7 +1645,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
                break;
        }
        case HTT_T2H_MSG_TYPE_RX_FRAG_IND: {
-               ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt event: ",
+               ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt event: ",
                                skb->data, skb->len);
                ath10k_htt_rx_frag_handler(htt, &resp->rx_frag_ind);
                break;
@@ -1609,7 +1662,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
                 * sends all tx frames as already inspected so this shouldn't
                 * happen unless fw has a bug.
                 */
-               ath10k_warn("received an unexpected htt tx inspect event\n");
+               ath10k_warn(ar, "received an unexpected htt tx inspect event\n");
                break;
        case HTT_T2H_MSG_TYPE_RX_ADDBA:
                ath10k_htt_rx_addba(ar, resp);
@@ -1624,9 +1677,9 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
                break;
        }
        default:
-               ath10k_dbg(ATH10K_DBG_HTT, "htt event (%d) not handled\n",
+               ath10k_dbg(ar, ATH10K_DBG_HTT, "htt event (%d) not handled\n",
                           resp->hdr.msg_type);
-               ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt event: ",
+               ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt event: ",
                                skb->data, skb->len);
                break;
        };
index 8b27bfcc1de39b3d3b86dc7881b532064e0a76f7..eaa73aa99c20e08816cad0905ef5dcd3e5b22e34 100644 (file)
@@ -58,6 +58,7 @@ exit:
 
 int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt)
 {
+       struct ath10k *ar = htt->ar;
        int msdu_id;
 
        lockdep_assert_held(&htt->tx_lock);
@@ -67,24 +68,29 @@ int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt)
        if (msdu_id == htt->max_num_pending_tx)
                return -ENOBUFS;
 
-       ath10k_dbg(ATH10K_DBG_HTT, "htt tx alloc msdu_id %d\n", msdu_id);
+       ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx alloc msdu_id %d\n", msdu_id);
        __set_bit(msdu_id, htt->used_msdu_ids);
        return msdu_id;
 }
 
 void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id)
 {
+       struct ath10k *ar = htt->ar;
+
        lockdep_assert_held(&htt->tx_lock);
 
        if (!test_bit(msdu_id, htt->used_msdu_ids))
-               ath10k_warn("trying to free unallocated msdu_id %d\n", msdu_id);
+               ath10k_warn(ar, "trying to free unallocated msdu_id %d\n",
+                           msdu_id);
 
-       ath10k_dbg(ATH10K_DBG_HTT, "htt tx free msdu_id %hu\n", msdu_id);
+       ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx free msdu_id %hu\n", msdu_id);
        __clear_bit(msdu_id, htt->used_msdu_ids);
 }
 
 int ath10k_htt_tx_alloc(struct ath10k_htt *htt)
 {
+       struct ath10k *ar = htt->ar;
+
        spin_lock_init(&htt->tx_lock);
        init_waitqueue_head(&htt->empty_tx_wq);
 
@@ -93,7 +99,7 @@ int ath10k_htt_tx_alloc(struct ath10k_htt *htt)
        else
                htt->max_num_pending_tx = TARGET_NUM_MSDU_DESC;
 
-       ath10k_dbg(ATH10K_DBG_BOOT, "htt tx max num pending tx %d\n",
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "htt tx max num pending tx %d\n",
                   htt->max_num_pending_tx);
 
        htt->pending_tx = kzalloc(sizeof(*htt->pending_tx) *
@@ -122,6 +128,7 @@ int ath10k_htt_tx_alloc(struct ath10k_htt *htt)
 
 static void ath10k_htt_tx_free_pending(struct ath10k_htt *htt)
 {
+       struct ath10k *ar = htt->ar;
        struct htt_tx_done tx_done = {0};
        int msdu_id;
 
@@ -130,7 +137,7 @@ static void ath10k_htt_tx_free_pending(struct ath10k_htt *htt)
                if (!test_bit(msdu_id, htt->used_msdu_ids))
                        continue;
 
-               ath10k_dbg(ATH10K_DBG_HTT, "force cleanup msdu_id %hu\n",
+               ath10k_dbg(ar, ATH10K_DBG_HTT, "force cleanup msdu_id %hu\n",
                           msdu_id);
 
                tx_done.discard = 1;
@@ -157,6 +164,7 @@ void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb)
 
 int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt)
 {
+       struct ath10k *ar = htt->ar;
        struct sk_buff *skb;
        struct htt_cmd *cmd;
        int len = 0;
@@ -165,7 +173,7 @@ int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt)
        len += sizeof(cmd->hdr);
        len += sizeof(cmd->ver_req);
 
-       skb = ath10k_htc_alloc_skb(len);
+       skb = ath10k_htc_alloc_skb(ar, len);
        if (!skb)
                return -ENOMEM;
 
@@ -184,6 +192,7 @@ int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt)
 
 int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie)
 {
+       struct ath10k *ar = htt->ar;
        struct htt_stats_req *req;
        struct sk_buff *skb;
        struct htt_cmd *cmd;
@@ -192,7 +201,7 @@ int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie)
        len += sizeof(cmd->hdr);
        len += sizeof(cmd->stats_req);
 
-       skb = ath10k_htc_alloc_skb(len);
+       skb = ath10k_htc_alloc_skb(ar, len);
        if (!skb)
                return -ENOMEM;
 
@@ -214,7 +223,8 @@ int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie)
 
        ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb);
        if (ret) {
-               ath10k_warn("failed to send htt type stats request: %d", ret);
+               ath10k_warn(ar, "failed to send htt type stats request: %d",
+                           ret);
                dev_kfree_skb_any(skb);
                return ret;
        }
@@ -224,6 +234,7 @@ int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie)
 
 int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt)
 {
+       struct ath10k *ar = htt->ar;
        struct sk_buff *skb;
        struct htt_cmd *cmd;
        struct htt_rx_ring_setup_ring *ring;
@@ -242,7 +253,7 @@ int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt)
 
        len = sizeof(cmd->hdr) + sizeof(cmd->rx_setup.hdr)
            + (sizeof(*ring) * num_rx_ring);
-       skb = ath10k_htc_alloc_skb(len);
+       skb = ath10k_htc_alloc_skb(ar, len);
        if (!skb)
                return -ENOMEM;
 
@@ -311,6 +322,7 @@ int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt,
                                u8 max_subfrms_ampdu,
                                u8 max_subfrms_amsdu)
 {
+       struct ath10k *ar = htt->ar;
        struct htt_aggr_conf *aggr_conf;
        struct sk_buff *skb;
        struct htt_cmd *cmd;
@@ -328,7 +340,7 @@ int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt,
        len = sizeof(cmd->hdr);
        len += sizeof(cmd->aggr_conf);
 
-       skb = ath10k_htc_alloc_skb(len);
+       skb = ath10k_htc_alloc_skb(ar, len);
        if (!skb)
                return -ENOMEM;
 
@@ -340,7 +352,7 @@ int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt,
        aggr_conf->max_num_ampdu_subframes = max_subfrms_ampdu;
        aggr_conf->max_num_amsdu_subframes = max_subfrms_amsdu;
 
-       ath10k_dbg(ATH10K_DBG_HTT, "htt h2t aggr cfg msg amsdu %d ampdu %d",
+       ath10k_dbg(ar, ATH10K_DBG_HTT, "htt h2t aggr cfg msg amsdu %d ampdu %d",
                   aggr_conf->max_num_amsdu_subframes,
                   aggr_conf->max_num_ampdu_subframes);
 
@@ -355,7 +367,8 @@ int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt,
 
 int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 {
-       struct device *dev = htt->ar->dev;
+       struct ath10k *ar = htt->ar;
+       struct device *dev = ar->dev;
        struct sk_buff *txdesc = NULL;
        struct htt_cmd *cmd;
        struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu);
@@ -382,7 +395,7 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
        htt->pending_tx[msdu_id] = msdu;
        spin_unlock_bh(&htt->tx_lock);
 
-       txdesc = ath10k_htc_alloc_skb(len);
+       txdesc = ath10k_htc_alloc_skb(ar, len);
        if (!txdesc) {
                res = -ENOMEM;
                goto err_free_msdu_id;
@@ -429,7 +442,8 @@ err:
 
 int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 {
-       struct device *dev = htt->ar->dev;
+       struct ath10k *ar = htt->ar;
+       struct device *dev = ar->dev;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data;
        struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu);
        struct ath10k_hif_sg_item sg_items[2];
@@ -545,11 +559,11 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
        skb_cb->htt.txbuf->cmd_tx.frags_paddr = __cpu_to_le32(frags_paddr);
        skb_cb->htt.txbuf->cmd_tx.peerid = __cpu_to_le32(HTT_INVALID_PEERID);
 
-       ath10k_dbg(ATH10K_DBG_HTT,
+       ath10k_dbg(ar, ATH10K_DBG_HTT,
                   "htt tx flags0 %hhu flags1 %hu len %d id %hu frags_paddr %08x, msdu_paddr %08x vdev %hhu tid %hhu\n",
                   flags0, flags1, msdu->len, msdu_id, frags_paddr,
                   (u32)skb_cb->paddr, vdev_id, tid);
-       ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt tx msdu: ",
+       ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt tx msdu: ",
                        msdu->data, msdu->len);
 
        sg_items[0].transfer_id = 0;
index 007e855f4ba99f9067725a11b85fdeadb3412483..13568b01de9feced302385eb4594f77e9e5ac4e9 100644 (file)
 #define QCA988X_HW_2_0_CHIP_ID_REV     0x2
 #define QCA988X_HW_2_0_FW_DIR          "ath10k/QCA988X/hw2.0"
 #define QCA988X_HW_2_0_FW_FILE         "firmware.bin"
-#define QCA988X_HW_2_0_FW_2_FILE       "firmware-2.bin"
+#define QCA988X_HW_2_0_FW_3_FILE       "firmware-3.bin"
 #define QCA988X_HW_2_0_OTP_FILE                "otp.bin"
 #define QCA988X_HW_2_0_BOARD_DATA_FILE "board.bin"
 #define QCA988X_HW_2_0_PATCH_LOAD_ADDR 0x1234
 
 #define ATH10K_FW_API2_FILE            "firmware-2.bin"
+#define ATH10K_FW_API3_FILE            "firmware-3.bin"
 
 /* includes also the null byte */
 #define ATH10K_FIRMWARE_MAGIC               "QCA-ATH10K"
 
+#define REG_DUMP_COUNT_QCA988X 60
+
 struct ath10k_fw_ie {
        __le32 id;
        __le32 len;
index 9d61bb157189bed0798170f8f5be5b76ead4387b..b858c8288196228c426e9f930586f63b774e7e78 100644 (file)
@@ -36,6 +36,7 @@ static int ath10k_send_key(struct ath10k_vif *arvif,
                           enum set_key_cmd cmd,
                           const u8 *macaddr)
 {
+       struct ath10k *ar = arvif->ar;
        struct wmi_vdev_install_key_arg arg = {
                .vdev_id = arvif->vdev_id,
                .key_idx = key->keyidx,
@@ -73,7 +74,7 @@ static int ath10k_send_key(struct ath10k_vif *arvif,
                        arg.key_flags = WMI_KEY_PAIRWISE;
                break;
        default:
-               ath10k_warn("cipher %d is not supported\n", key->cipher);
+               ath10k_warn(ar, "cipher %d is not supported\n", key->cipher);
                return -EOPNOTSUPP;
        }
 
@@ -168,7 +169,7 @@ static int ath10k_clear_peer_keys(struct ath10k_vif *arvif,
                        first_errno = ret;
 
                if (ret)
-                       ath10k_warn("failed to remove peer wep key %d: %d\n",
+                       ath10k_warn(ar, "failed to remove peer wep key %d: %d\n",
                                    i, ret);
 
                peer->keys[i] = NULL;
@@ -216,7 +217,7 @@ static int ath10k_clear_vdev_key(struct ath10k_vif *arvif,
                        first_errno = ret;
 
                if (ret)
-                       ath10k_warn("failed to remove key for %pM: %d\n",
+                       ath10k_warn(ar, "failed to remove key for %pM: %d\n",
                                    addr, ret);
        }
 
@@ -327,14 +328,14 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr)
 
        ret = ath10k_wmi_peer_create(ar, vdev_id, addr);
        if (ret) {
-               ath10k_warn("failed to create wmi peer %pM on vdev %i: %i\n",
+               ath10k_warn(ar, "failed to create wmi peer %pM on vdev %i: %i\n",
                            addr, vdev_id, ret);
                return ret;
        }
 
        ret = ath10k_wait_for_peer_created(ar, vdev_id, addr);
        if (ret) {
-               ath10k_warn("failed to wait for created wmi peer %pM on vdev %i: %i\n",
+               ath10k_warn(ar, "failed to wait for created wmi peer %pM on vdev %i: %i\n",
                            addr, vdev_id, ret);
                return ret;
        }
@@ -355,7 +356,7 @@ static int ath10k_mac_set_kickout(struct ath10k_vif *arvif)
        ret = ath10k_wmi_pdev_set_param(ar, param,
                                        ATH10K_KICKOUT_THRESHOLD);
        if (ret) {
-               ath10k_warn("failed to set kickout threshold on vdev %i: %d\n",
+               ath10k_warn(ar, "failed to set kickout threshold on vdev %i: %d\n",
                            arvif->vdev_id, ret);
                return ret;
        }
@@ -364,7 +365,7 @@ static int ath10k_mac_set_kickout(struct ath10k_vif *arvif)
        ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param,
                                        ATH10K_KEEPALIVE_MIN_IDLE);
        if (ret) {
-               ath10k_warn("failed to set keepalive minimum idle time on vdev %i: %d\n",
+               ath10k_warn(ar, "failed to set keepalive minimum idle time on vdev %i: %d\n",
                            arvif->vdev_id, ret);
                return ret;
        }
@@ -373,7 +374,7 @@ static int ath10k_mac_set_kickout(struct ath10k_vif *arvif)
        ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param,
                                        ATH10K_KEEPALIVE_MAX_IDLE);
        if (ret) {
-               ath10k_warn("failed to set keepalive maximum idle time on vdev %i: %d\n",
+               ath10k_warn(ar, "failed to set keepalive maximum idle time on vdev %i: %d\n",
                            arvif->vdev_id, ret);
                return ret;
        }
@@ -382,7 +383,7 @@ static int ath10k_mac_set_kickout(struct ath10k_vif *arvif)
        ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param,
                                        ATH10K_KEEPALIVE_MAX_UNRESPONSIVE);
        if (ret) {
-               ath10k_warn("failed to set keepalive maximum unresponsive time on vdev %i: %d\n",
+               ath10k_warn(ar, "failed to set keepalive maximum unresponsive time on vdev %i: %d\n",
                            arvif->vdev_id, ret);
                return ret;
        }
@@ -449,7 +450,7 @@ static void ath10k_peer_cleanup(struct ath10k *ar, u32 vdev_id)
                if (peer->vdev_id != vdev_id)
                        continue;
 
-               ath10k_warn("removing stale peer %pM from vdev_id %d\n",
+               ath10k_warn(ar, "removing stale peer %pM from vdev_id %d\n",
                            peer->addr, vdev_id);
 
                list_del(&peer->list);
@@ -496,7 +497,7 @@ static bool ath10k_monitor_is_enabled(struct ath10k *ar)
 {
        lockdep_assert_held(&ar->conf_mutex);
 
-       ath10k_dbg(ATH10K_DBG_MAC,
+       ath10k_dbg(ar, ATH10K_DBG_MAC,
                   "mac monitor refs: promisc %d monitor %d cac %d\n",
                   ar->promisc, ar->monitor,
                   test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags));
@@ -531,35 +532,35 @@ static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id)
 
        ret = ath10k_wmi_vdev_start(ar, &arg);
        if (ret) {
-               ath10k_warn("failed to request monitor vdev %i start: %d\n",
+               ath10k_warn(ar, "failed to request monitor vdev %i start: %d\n",
                            vdev_id, ret);
                return ret;
        }
 
        ret = ath10k_vdev_setup_sync(ar);
        if (ret) {
-               ath10k_warn("failed to synchronize setup for monitor vdev %i: %d\n",
+               ath10k_warn(ar, "failed to synchronize setup for monitor vdev %i: %d\n",
                            vdev_id, ret);
                return ret;
        }
 
        ret = ath10k_wmi_vdev_up(ar, vdev_id, 0, ar->mac_addr);
        if (ret) {
-               ath10k_warn("failed to put up monitor vdev %i: %d\n",
+               ath10k_warn(ar, "failed to put up monitor vdev %i: %d\n",
                            vdev_id, ret);
                goto vdev_stop;
        }
 
        ar->monitor_vdev_id = vdev_id;
 
-       ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %i started\n",
+       ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %i started\n",
                   ar->monitor_vdev_id);
        return 0;
 
 vdev_stop:
        ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id);
        if (ret)
-               ath10k_warn("failed to stop monitor vdev %i after start failure: %d\n",
+               ath10k_warn(ar, "failed to stop monitor vdev %i after start failure: %d\n",
                            ar->monitor_vdev_id, ret);
 
        return ret;
@@ -573,20 +574,20 @@ static int ath10k_monitor_vdev_stop(struct ath10k *ar)
 
        ret = ath10k_wmi_vdev_down(ar, ar->monitor_vdev_id);
        if (ret)
-               ath10k_warn("failed to put down monitor vdev %i: %d\n",
+               ath10k_warn(ar, "failed to put down monitor vdev %i: %d\n",
                            ar->monitor_vdev_id, ret);
 
        ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id);
        if (ret)
-               ath10k_warn("failed to to request monitor vdev %i stop: %d\n",
+               ath10k_warn(ar, "failed to to request monitor vdev %i stop: %d\n",
                            ar->monitor_vdev_id, ret);
 
        ret = ath10k_vdev_setup_sync(ar);
        if (ret)
-               ath10k_warn("failed to synchronise monitor vdev %i: %d\n",
+               ath10k_warn(ar, "failed to synchronise monitor vdev %i: %d\n",
                            ar->monitor_vdev_id, ret);
 
-       ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %i stopped\n",
+       ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %i stopped\n",
                   ar->monitor_vdev_id);
        return ret;
 }
@@ -597,35 +598,29 @@ static int ath10k_monitor_vdev_create(struct ath10k *ar)
 
        lockdep_assert_held(&ar->conf_mutex);
 
-       bit = ffs(ar->free_vdev_map);
-       if (bit == 0) {
-               ath10k_warn("failed to find free vdev id for monitor vdev\n");
+       if (ar->free_vdev_map == 0) {
+               ath10k_warn(ar, "failed to find free vdev id for monitor vdev\n");
                return -ENOMEM;
        }
 
+       bit = ffs(ar->free_vdev_map);
+
        ar->monitor_vdev_id = bit - 1;
-       ar->free_vdev_map &= ~(1 << ar->monitor_vdev_id);
 
        ret = ath10k_wmi_vdev_create(ar, ar->monitor_vdev_id,
                                     WMI_VDEV_TYPE_MONITOR,
                                     0, ar->mac_addr);
        if (ret) {
-               ath10k_warn("failed to request monitor vdev %i creation: %d\n",
+               ath10k_warn(ar, "failed to request monitor vdev %i creation: %d\n",
                            ar->monitor_vdev_id, ret);
-               goto vdev_fail;
+               return ret;
        }
 
-       ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %d created\n",
+       ar->free_vdev_map &= ~(1 << ar->monitor_vdev_id);
+       ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %d created\n",
                   ar->monitor_vdev_id);
 
        return 0;
-
-vdev_fail:
-       /*
-        * Restore the ID to the global map.
-        */
-       ar->free_vdev_map |= 1 << (ar->monitor_vdev_id);
-       return ret;
 }
 
 static int ath10k_monitor_vdev_delete(struct ath10k *ar)
@@ -636,14 +631,14 @@ static int ath10k_monitor_vdev_delete(struct ath10k *ar)
 
        ret = ath10k_wmi_vdev_delete(ar, ar->monitor_vdev_id);
        if (ret) {
-               ath10k_warn("failed to request wmi monitor vdev %i removal: %d\n",
+               ath10k_warn(ar, "failed to request wmi monitor vdev %i removal: %d\n",
                            ar->monitor_vdev_id, ret);
                return ret;
        }
 
-       ar->free_vdev_map |= 1 << (ar->monitor_vdev_id);
+       ar->free_vdev_map |= 1 << ar->monitor_vdev_id;
 
-       ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %d deleted\n",
+       ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %d deleted\n",
                   ar->monitor_vdev_id);
        return ret;
 }
@@ -655,30 +650,30 @@ static int ath10k_monitor_start(struct ath10k *ar)
        lockdep_assert_held(&ar->conf_mutex);
 
        if (!ath10k_monitor_is_enabled(ar)) {
-               ath10k_warn("trying to start monitor with no references\n");
+               ath10k_warn(ar, "trying to start monitor with no references\n");
                return 0;
        }
 
        if (ar->monitor_started) {
-               ath10k_dbg(ATH10K_DBG_MAC, "mac monitor already started\n");
+               ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor already started\n");
                return 0;
        }
 
        ret = ath10k_monitor_vdev_create(ar);
        if (ret) {
-               ath10k_warn("failed to create monitor vdev: %d\n", ret);
+               ath10k_warn(ar, "failed to create monitor vdev: %d\n", ret);
                return ret;
        }
 
        ret = ath10k_monitor_vdev_start(ar, ar->monitor_vdev_id);
        if (ret) {
-               ath10k_warn("failed to start monitor vdev: %d\n", ret);
+               ath10k_warn(ar, "failed to start monitor vdev: %d\n", ret);
                ath10k_monitor_vdev_delete(ar);
                return ret;
        }
 
        ar->monitor_started = true;
-       ath10k_dbg(ATH10K_DBG_MAC, "mac monitor started\n");
+       ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor started\n");
 
        return 0;
 }
@@ -690,27 +685,27 @@ static void ath10k_monitor_stop(struct ath10k *ar)
        lockdep_assert_held(&ar->conf_mutex);
 
        if (ath10k_monitor_is_enabled(ar)) {
-               ath10k_dbg(ATH10K_DBG_MAC,
+               ath10k_dbg(ar, ATH10K_DBG_MAC,
                           "mac monitor will be stopped later\n");
                return;
        }
 
        if (!ar->monitor_started) {
-               ath10k_dbg(ATH10K_DBG_MAC,
+               ath10k_dbg(ar, ATH10K_DBG_MAC,
                           "mac monitor probably failed to start earlier\n");
                return;
        }
 
        ret = ath10k_monitor_vdev_stop(ar);
        if (ret)
-               ath10k_warn("failed to stop monitor vdev: %d\n", ret);
+               ath10k_warn(ar, "failed to stop monitor vdev: %d\n", ret);
 
        ret = ath10k_monitor_vdev_delete(ar);
        if (ret)
-               ath10k_warn("failed to delete monitor vdev: %d\n", ret);
+               ath10k_warn(ar, "failed to delete monitor vdev: %d\n", ret);
 
        ar->monitor_started = false;
-       ath10k_dbg(ATH10K_DBG_MAC, "mac monitor stopped\n");
+       ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor stopped\n");
 }
 
 static int ath10k_recalc_rtscts_prot(struct ath10k_vif *arvif)
@@ -743,12 +738,12 @@ static int ath10k_start_cac(struct ath10k *ar)
 
        ret = ath10k_monitor_start(ar);
        if (ret) {
-               ath10k_warn("failed to start monitor (cac): %d\n", ret);
+               ath10k_warn(ar, "failed to start monitor (cac): %d\n", ret);
                clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
                return ret;
        }
 
-       ath10k_dbg(ATH10K_DBG_MAC, "mac cac start monitor vdev %d\n",
+       ath10k_dbg(ar, ATH10K_DBG_MAC, "mac cac start monitor vdev %d\n",
                   ar->monitor_vdev_id);
 
        return 0;
@@ -765,7 +760,7 @@ static int ath10k_stop_cac(struct ath10k *ar)
        clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
        ath10k_monitor_stop(ar);
 
-       ath10k_dbg(ATH10K_DBG_MAC, "mac cac finished\n");
+       ath10k_dbg(ar, ATH10K_DBG_MAC, "mac cac finished\n");
 
        return 0;
 }
@@ -791,12 +786,12 @@ static void ath10k_recalc_radar_detection(struct ath10k *ar)
                 * radiation is not allowed, make this channel DFS_UNAVAILABLE
                 * by indicating that radar was detected.
                 */
-               ath10k_warn("failed to start CAC: %d\n", ret);
+               ath10k_warn(ar, "failed to start CAC: %d\n", ret);
                ieee80211_radar_detected(ar->hw);
        }
 }
 
-static int ath10k_vdev_start(struct ath10k_vif *arvif)
+static int ath10k_vdev_start_restart(struct ath10k_vif *arvif, bool restart)
 {
        struct ath10k *ar = arvif->ar;
        struct cfg80211_chan_def *chandef = &ar->chandef;
@@ -833,21 +828,25 @@ static int ath10k_vdev_start(struct ath10k_vif *arvif)
                arg.ssid_len = arvif->vif->bss_conf.ssid_len;
        }
 
-       ath10k_dbg(ATH10K_DBG_MAC,
+       ath10k_dbg(ar, ATH10K_DBG_MAC,
                   "mac vdev %d start center_freq %d phymode %s\n",
                   arg.vdev_id, arg.channel.freq,
                   ath10k_wmi_phymode_str(arg.channel.mode));
 
-       ret = ath10k_wmi_vdev_start(ar, &arg);
+       if (restart)
+               ret = ath10k_wmi_vdev_restart(ar, &arg);
+       else
+               ret = ath10k_wmi_vdev_start(ar, &arg);
+
        if (ret) {
-               ath10k_warn("failed to start WMI vdev %i: %d\n",
+               ath10k_warn(ar, "failed to start WMI vdev %i: %d\n",
                            arg.vdev_id, ret);
                return ret;
        }
 
        ret = ath10k_vdev_setup_sync(ar);
        if (ret) {
-               ath10k_warn("failed to synchronise setup for vdev %i: %d\n",
+               ath10k_warn(ar, "failed to synchronise setup for vdev %i: %d\n",
                            arg.vdev_id, ret);
                return ret;
        }
@@ -858,6 +857,16 @@ static int ath10k_vdev_start(struct ath10k_vif *arvif)
        return ret;
 }
 
+static int ath10k_vdev_start(struct ath10k_vif *arvif)
+{
+       return ath10k_vdev_start_restart(arvif, false);
+}
+
+static int ath10k_vdev_restart(struct ath10k_vif *arvif)
+{
+       return ath10k_vdev_start_restart(arvif, true);
+}
+
 static int ath10k_vdev_stop(struct ath10k_vif *arvif)
 {
        struct ath10k *ar = arvif->ar;
@@ -869,14 +878,14 @@ static int ath10k_vdev_stop(struct ath10k_vif *arvif)
 
        ret = ath10k_wmi_vdev_stop(ar, arvif->vdev_id);
        if (ret) {
-               ath10k_warn("failed to stop WMI vdev %i: %d\n",
+               ath10k_warn(ar, "failed to stop WMI vdev %i: %d\n",
                            arvif->vdev_id, ret);
                return ret;
        }
 
        ret = ath10k_vdev_setup_sync(ar);
        if (ret) {
-               ath10k_warn("failed to syncronise setup for vdev %i: %d\n",
+               ath10k_warn(ar, "failed to syncronise setup for vdev %i: %d\n",
                            arvif->vdev_id, ret);
                return ret;
        }
@@ -894,6 +903,7 @@ static int ath10k_vdev_stop(struct ath10k_vif *arvif)
 static void ath10k_control_beaconing(struct ath10k_vif *arvif,
                                struct ieee80211_bss_conf *info)
 {
+       struct ath10k *ar = arvif->ar;
        int ret = 0;
 
        lockdep_assert_held(&arvif->ar->conf_mutex);
@@ -931,7 +941,7 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif,
        ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
                                 arvif->bssid);
        if (ret) {
-               ath10k_warn("failed to bring up vdev %d: %i\n",
+               ath10k_warn(ar, "failed to bring up vdev %d: %i\n",
                            arvif->vdev_id, ret);
                ath10k_vdev_stop(arvif);
                return;
@@ -940,13 +950,14 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif,
        arvif->is_started = true;
        arvif->is_up = true;
 
-       ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d up\n", arvif->vdev_id);
+       ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d up\n", arvif->vdev_id);
 }
 
 static void ath10k_control_ibss(struct ath10k_vif *arvif,
                                struct ieee80211_bss_conf *info,
                                const u8 self_peer[ETH_ALEN])
 {
+       struct ath10k *ar = arvif->ar;
        u32 vdev_param;
        int ret = 0;
 
@@ -955,7 +966,7 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
        if (!info->ibss_joined) {
                ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, self_peer);
                if (ret)
-                       ath10k_warn("failed to delete IBSS self peer %pM for vdev %d: %d\n",
+                       ath10k_warn(ar, "failed to delete IBSS self peer %pM for vdev %d: %d\n",
                                    self_peer, arvif->vdev_id, ret);
 
                if (is_zero_ether_addr(arvif->bssid))
@@ -964,7 +975,7 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
                ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id,
                                         arvif->bssid);
                if (ret) {
-                       ath10k_warn("failed to delete IBSS BSSID peer %pM for vdev %d: %d\n",
+                       ath10k_warn(ar, "failed to delete IBSS BSSID peer %pM for vdev %d: %d\n",
                                    arvif->bssid, arvif->vdev_id, ret);
                        return;
                }
@@ -976,7 +987,7 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
 
        ret = ath10k_peer_create(arvif->ar, arvif->vdev_id, self_peer);
        if (ret) {
-               ath10k_warn("failed to create IBSS self peer %pM for vdev %d: %d\n",
+               ath10k_warn(ar, "failed to create IBSS self peer %pM for vdev %d: %d\n",
                            self_peer, arvif->vdev_id, ret);
                return;
        }
@@ -985,7 +996,7 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
        ret = ath10k_wmi_vdev_set_param(arvif->ar, arvif->vdev_id, vdev_param,
                                        ATH10K_DEFAULT_ATIM);
        if (ret)
-               ath10k_warn("failed to set IBSS ATIM for vdev %d: %d\n",
+               ath10k_warn(ar, "failed to set IBSS ATIM for vdev %d: %d\n",
                            arvif->vdev_id, ret);
 }
 
@@ -1012,7 +1023,7 @@ static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif)
                ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param,
                                                  conf->dynamic_ps_timeout);
                if (ret) {
-                       ath10k_warn("failed to set inactivity time for vdev %d: %i\n",
+                       ath10k_warn(ar, "failed to set inactivity time for vdev %d: %i\n",
                                    arvif->vdev_id, ret);
                        return ret;
                }
@@ -1020,12 +1031,12 @@ static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif)
                psmode = WMI_STA_PS_MODE_DISABLED;
        }
 
-       ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d psmode %s\n",
+       ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d psmode %s\n",
                   arvif->vdev_id, psmode ? "enable" : "disable");
 
        ret = ath10k_wmi_set_psmode(ar, arvif->vdev_id, psmode);
        if (ret) {
-               ath10k_warn("failed to set PS Mode %d for vdev %d: %d\n",
+               ath10k_warn(ar, "failed to set PS Mode %d for vdev %d: %d\n",
                            psmode, arvif->vdev_id, ret);
                return ret;
        }
@@ -1109,12 +1120,12 @@ static void ath10k_peer_assoc_h_crypto(struct ath10k *ar,
 
        /* FIXME: base on RSN IE/WPA IE is a correct idea? */
        if (rsnie || wpaie) {
-               ath10k_dbg(ATH10K_DBG_WMI, "%s: rsn ie found\n", __func__);
+               ath10k_dbg(ar, ATH10K_DBG_WMI, "%s: rsn ie found\n", __func__);
                arg->peer_flags |= WMI_PEER_NEED_PTK_4_WAY;
        }
 
        if (wpaie) {
-               ath10k_dbg(ATH10K_DBG_WMI, "%s: wpa ie found\n", __func__);
+               ath10k_dbg(ar, ATH10K_DBG_WMI, "%s: wpa ie found\n", __func__);
                arg->peer_flags |= WMI_PEER_NEED_GTK_2_WAY;
        }
 }
@@ -1223,7 +1234,7 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
                arg->peer_num_spatial_streams = sta->rx_nss;
        }
 
-       ath10k_dbg(ATH10K_DBG_MAC, "mac ht peer %pM mcs cnt %d nss %d\n",
+       ath10k_dbg(ar, ATH10K_DBG_MAC, "mac ht peer %pM mcs cnt %d nss %d\n",
                   arg->addr,
                   arg->peer_ht_rates.num_rates,
                   arg->peer_num_spatial_streams);
@@ -1240,7 +1251,7 @@ static int ath10k_peer_assoc_qos_ap(struct ath10k *ar,
        lockdep_assert_held(&ar->conf_mutex);
 
        if (sta->wme && sta->uapsd_queues) {
-               ath10k_dbg(ATH10K_DBG_MAC, "mac uapsd_queues 0x%x max_sp %d\n",
+               ath10k_dbg(ar, ATH10K_DBG_MAC, "mac uapsd_queues 0x%x max_sp %d\n",
                           sta->uapsd_queues, sta->max_sp);
 
                if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
@@ -1265,7 +1276,7 @@ static int ath10k_peer_assoc_qos_ap(struct ath10k *ar,
                                                 WMI_AP_PS_PEER_PARAM_UAPSD,
                                                 uapsd);
                if (ret) {
-                       ath10k_warn("failed to set ap ps peer param uapsd for vdev %i: %d\n",
+                       ath10k_warn(ar, "failed to set ap ps peer param uapsd for vdev %i: %d\n",
                                    arvif->vdev_id, ret);
                        return ret;
                }
@@ -1275,7 +1286,7 @@ static int ath10k_peer_assoc_qos_ap(struct ath10k *ar,
                                                 WMI_AP_PS_PEER_PARAM_MAX_SP,
                                                 max_sp);
                if (ret) {
-                       ath10k_warn("failed to set ap ps peer param max sp for vdev %i: %d\n",
+                       ath10k_warn(ar, "failed to set ap ps peer param max sp for vdev %i: %d\n",
                                    arvif->vdev_id, ret);
                        return ret;
                }
@@ -1287,7 +1298,7 @@ static int ath10k_peer_assoc_qos_ap(struct ath10k *ar,
                ret = ath10k_wmi_set_ap_ps_param(ar, arvif->vdev_id, sta->addr,
                                        WMI_AP_PS_PEER_PARAM_AGEOUT_TIME, 10);
                if (ret) {
-                       ath10k_warn("failed to set ap ps peer param ageout time for vdev %i: %d\n",
+                       ath10k_warn(ar, "failed to set ap ps peer param ageout time for vdev %i: %d\n",
                                    arvif->vdev_id, ret);
                        return ret;
                }
@@ -1334,7 +1345,7 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar,
        arg->peer_vht_rates.tx_mcs_set =
                __le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map);
 
-       ath10k_dbg(ATH10K_DBG_MAC, "mac vht peer %pM max_mpdu %d flags 0x%x\n",
+       ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vht peer %pM max_mpdu %d flags 0x%x\n",
                   sta->addr, arg->peer_max_mpdu, arg->peer_flags);
 }
 
@@ -1407,7 +1418,7 @@ static void ath10k_peer_assoc_h_phymode(struct ath10k *ar,
                break;
        }
 
-       ath10k_dbg(ATH10K_DBG_MAC, "mac peer %pM phymode %s\n",
+       ath10k_dbg(ar, ATH10K_DBG_MAC, "mac peer %pM phymode %s\n",
                   sta->addr, ath10k_wmi_phymode_str(phymode));
 
        arg->peer_phymode = phymode;
@@ -1480,7 +1491,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
 
        ap_sta = ieee80211_find_sta(vif, bss_conf->bssid);
        if (!ap_sta) {
-               ath10k_warn("failed to find station entry for bss %pM vdev %i\n",
+               ath10k_warn(ar, "failed to find station entry for bss %pM vdev %i\n",
                            bss_conf->bssid, arvif->vdev_id);
                rcu_read_unlock();
                return;
@@ -1493,7 +1504,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
        ret = ath10k_peer_assoc_prepare(ar, arvif, ap_sta,
                                        bss_conf, &peer_arg);
        if (ret) {
-               ath10k_warn("failed to prepare peer assoc for %pM vdev %i: %d\n",
+               ath10k_warn(ar, "failed to prepare peer assoc for %pM vdev %i: %d\n",
                            bss_conf->bssid, arvif->vdev_id, ret);
                rcu_read_unlock();
                return;
@@ -1503,19 +1514,19 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
 
        ret = ath10k_wmi_peer_assoc(ar, &peer_arg);
        if (ret) {
-               ath10k_warn("failed to run peer assoc for %pM vdev %i: %d\n",
+               ath10k_warn(ar, "failed to run peer assoc for %pM vdev %i: %d\n",
                            bss_conf->bssid, arvif->vdev_id, ret);
                return;
        }
 
        ret = ath10k_setup_peer_smps(ar, arvif, bss_conf->bssid, &ht_cap);
        if (ret) {
-               ath10k_warn("failed to setup peer SMPS for vdev %i: %d\n",
+               ath10k_warn(ar, "failed to setup peer SMPS for vdev %i: %d\n",
                            arvif->vdev_id, ret);
                return;
        }
 
-       ath10k_dbg(ATH10K_DBG_MAC,
+       ath10k_dbg(ar, ATH10K_DBG_MAC,
                   "mac vdev %d up (associated) bssid %pM aid %d\n",
                   arvif->vdev_id, bss_conf->bssid, bss_conf->aid);
 
@@ -1524,7 +1535,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
 
        ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, arvif->aid, arvif->bssid);
        if (ret) {
-               ath10k_warn("failed to set vdev %d up: %d\n",
+               ath10k_warn(ar, "failed to set vdev %d up: %d\n",
                            arvif->vdev_id, ret);
                return;
        }
@@ -1550,7 +1561,7 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
         * No idea why this happens, even though VDEV-DOWN is supposed
         * to be analogous to link down, so just stop the VDEV.
         */
-       ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d stop (disassociated\n",
+       ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d stop (disassociated\n",
                   arvif->vdev_id);
 
        /* FIXME: check return value */
@@ -1563,7 +1574,7 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
         * interfaces as it expects there is no rx when no interface is
         * running.
         */
-       ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d down\n", arvif->vdev_id);
+       ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d down\n", arvif->vdev_id);
 
        /* FIXME: why don't we print error if wmi call fails? */
        ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
@@ -1584,7 +1595,7 @@ static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
 
        ret = ath10k_peer_assoc_prepare(ar, arvif, sta, NULL, &peer_arg);
        if (ret) {
-               ath10k_warn("failed to prepare WMI peer assoc for %pM vdev %i: %i\n",
+               ath10k_warn(ar, "failed to prepare WMI peer assoc for %pM vdev %i: %i\n",
                            sta->addr, arvif->vdev_id, ret);
                return ret;
        }
@@ -1592,14 +1603,14 @@ static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
        peer_arg.peer_reassoc = reassoc;
        ret = ath10k_wmi_peer_assoc(ar, &peer_arg);
        if (ret) {
-               ath10k_warn("failed to run peer assoc for STA %pM vdev %i: %d\n",
+               ath10k_warn(ar, "failed to run peer assoc for STA %pM vdev %i: %d\n",
                            sta->addr, arvif->vdev_id, ret);
                return ret;
        }
 
        ret = ath10k_setup_peer_smps(ar, arvif, sta->addr, &sta->ht_cap);
        if (ret) {
-               ath10k_warn("failed to setup peer SMPS for vdev %d: %d\n",
+               ath10k_warn(ar, "failed to setup peer SMPS for vdev %d: %d\n",
                            arvif->vdev_id, ret);
                return ret;
        }
@@ -1608,7 +1619,7 @@ static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
                arvif->num_legacy_stations++;
                ret  = ath10k_recalc_rtscts_prot(arvif);
                if (ret) {
-                       ath10k_warn("failed to recalculate rts/cts prot for vdev %d: %d\n",
+                       ath10k_warn(ar, "failed to recalculate rts/cts prot for vdev %d: %d\n",
                                    arvif->vdev_id, ret);
                        return ret;
                }
@@ -1616,14 +1627,14 @@ static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
 
        ret = ath10k_install_peer_wep_keys(arvif, sta->addr);
        if (ret) {
-               ath10k_warn("failed to install peer wep keys for vdev %i: %d\n",
+               ath10k_warn(ar, "failed to install peer wep keys for vdev %i: %d\n",
                            arvif->vdev_id, ret);
                return ret;
        }
 
        ret = ath10k_peer_assoc_qos_ap(ar, arvif, sta);
        if (ret) {
-               ath10k_warn("failed to set qos params for STA %pM for vdev %i: %d\n",
+               ath10k_warn(ar, "failed to set qos params for STA %pM for vdev %i: %d\n",
                            sta->addr, arvif->vdev_id, ret);
                return ret;
        }
@@ -1642,7 +1653,7 @@ static int ath10k_station_disassoc(struct ath10k *ar, struct ath10k_vif *arvif,
                arvif->num_legacy_stations--;
                ret = ath10k_recalc_rtscts_prot(arvif);
                if (ret) {
-                       ath10k_warn("failed to recalculate rts/cts prot for vdev %d: %d\n",
+                       ath10k_warn(ar, "failed to recalculate rts/cts prot for vdev %d: %d\n",
                                    arvif->vdev_id, ret);
                        return ret;
                }
@@ -1650,7 +1661,7 @@ static int ath10k_station_disassoc(struct ath10k *ar, struct ath10k_vif *arvif,
 
        ret = ath10k_clear_peer_keys(arvif, sta->addr);
        if (ret) {
-               ath10k_warn("failed to clear all peer wep keys for vdev %i: %d\n",
+               ath10k_warn(ar, "failed to clear all peer wep keys for vdev %i: %d\n",
                            arvif->vdev_id, ret);
                return ret;
        }
@@ -1742,7 +1753,7 @@ static int ath10k_update_channel_list(struct ath10k *ar)
                        if (WARN_ON_ONCE(ch->mode == MODE_UNKNOWN))
                                continue;
 
-                       ath10k_dbg(ATH10K_DBG_WMI,
+                       ath10k_dbg(ar, ATH10K_DBG_WMI,
                                   "mac channel [%zd/%d] freq %d maxpower %d regpower %d antenna %d mode %d\n",
                                    ch - arg.channels, arg.n_channels,
                                   ch->freq, ch->max_power, ch->max_reg_power,
@@ -1785,7 +1796,7 @@ static void ath10k_regd_update(struct ath10k *ar)
 
        ret = ath10k_update_channel_list(ar);
        if (ret)
-               ath10k_warn("failed to update channel list: %d\n", ret);
+               ath10k_warn(ar, "failed to update channel list: %d\n", ret);
 
        regpair = ar->ath_common.regulatory.regpair;
 
@@ -1806,7 +1817,7 @@ static void ath10k_regd_update(struct ath10k *ar)
                                            regpair->reg_5ghz_ctl,
                                            wmi_dfs_reg);
        if (ret)
-               ath10k_warn("failed to set pdev regdomain: %d\n", ret);
+               ath10k_warn(ar, "failed to set pdev regdomain: %d\n", ret);
 }
 
 static void ath10k_reg_notifier(struct wiphy *wiphy,
@@ -1819,12 +1830,12 @@ static void ath10k_reg_notifier(struct wiphy *wiphy,
        ath_reg_notifier_apply(wiphy, request, &ar->ath_common.regulatory);
 
        if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector) {
-               ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs region 0x%x\n",
+               ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "dfs region 0x%x\n",
                           request->dfs_region);
                result = ar->dfs_detector->set_dfs_domain(ar->dfs_detector,
                                                          request->dfs_region);
                if (!result)
-                       ath10k_warn("DFS region 0x%X not supported, will trigger radar for every pulse\n",
+                       ath10k_warn(ar, "DFS region 0x%X not supported, will trigger radar for every pulse\n",
                                    request->dfs_region);
        }
 
@@ -1861,7 +1872,7 @@ static u8 ath10k_tx_h_get_vdev_id(struct ath10k *ar,
        if (ar->monitor_started)
                return ar->monitor_vdev_id;
 
-       ath10k_warn("failed to resolve vdev id\n");
+       ath10k_warn(ar, "failed to resolve vdev id\n");
        return 0;
 }
 
@@ -1897,6 +1908,7 @@ static void ath10k_tx_wep_key_work(struct work_struct *work)
 {
        struct ath10k_vif *arvif = container_of(work, struct ath10k_vif,
                                                wep_key_work);
+       struct ath10k *ar = arvif->ar;
        int ret, keyidx = arvif->def_wep_key_newidx;
 
        mutex_lock(&arvif->ar->conf_mutex);
@@ -1907,7 +1919,7 @@ static void ath10k_tx_wep_key_work(struct work_struct *work)
        if (arvif->def_wep_key_idx == keyidx)
                goto unlock;
 
-       ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d set keyidx %d\n",
+       ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d set keyidx %d\n",
                   arvif->vdev_id, keyidx);
 
        ret = ath10k_wmi_vdev_set_param(arvif->ar,
@@ -1915,7 +1927,7 @@ static void ath10k_tx_wep_key_work(struct work_struct *work)
                                        arvif->ar->wmi.vdev_param->def_keyid,
                                        keyidx);
        if (ret) {
-               ath10k_warn("failed to update wep key index for vdev %d: %d\n",
+               ath10k_warn(ar, "failed to update wep key index for vdev %d: %d\n",
                            arvif->vdev_id,
                            ret);
                goto unlock;
@@ -1995,7 +2007,7 @@ static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb)
                             ar->fw_features)) {
                        if (skb_queue_len(&ar->wmi_mgmt_tx_queue) >=
                            ATH10K_MAX_NUM_MGMT_PENDING) {
-                               ath10k_warn("reached WMI management tranmist queue limit\n");
+                               ath10k_warn(ar, "reached WMI management transmit queue limit\n");
                                ret = -EBUSY;
                                goto exit;
                        }
@@ -2019,7 +2031,8 @@ static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb)
 
 exit:
        if (ret) {
-               ath10k_warn("failed to transmit packet, dropping: %d\n", ret);
+               ath10k_warn(ar, "failed to transmit packet, dropping: %d\n",
+                           ret);
                ieee80211_free_txskb(ar->hw, skb);
        }
 }
@@ -2061,7 +2074,7 @@ void ath10k_offchan_tx_work(struct work_struct *work)
 
                mutex_lock(&ar->conf_mutex);
 
-               ath10k_dbg(ATH10K_DBG_MAC, "mac offchannel skb %p\n",
+               ath10k_dbg(ar, ATH10K_DBG_MAC, "mac offchannel skb %p\n",
                           skb);
 
                hdr = (struct ieee80211_hdr *)skb->data;
@@ -2074,13 +2087,13 @@ void ath10k_offchan_tx_work(struct work_struct *work)
 
                if (peer)
                        /* FIXME: should this use ath10k_warn()? */
-                       ath10k_dbg(ATH10K_DBG_MAC, "peer %pM on vdev %d already present\n",
+                       ath10k_dbg(ar, ATH10K_DBG_MAC, "peer %pM on vdev %d already present\n",
                                   peer_addr, vdev_id);
 
                if (!peer) {
                        ret = ath10k_peer_create(ar, vdev_id, peer_addr);
                        if (ret)
-                               ath10k_warn("failed to create peer %pM on vdev %d: %d\n",
+                               ath10k_warn(ar, "failed to create peer %pM on vdev %d: %d\n",
                                            peer_addr, vdev_id, ret);
                }
 
@@ -2094,13 +2107,13 @@ void ath10k_offchan_tx_work(struct work_struct *work)
                ret = wait_for_completion_timeout(&ar->offchan_tx_completed,
                                                  3 * HZ);
                if (ret <= 0)
-                       ath10k_warn("timed out waiting for offchannel skb %p\n",
+                       ath10k_warn(ar, "timed out waiting for offchannel skb %p\n",
                                    skb);
 
                if (!peer) {
                        ret = ath10k_peer_delete(ar, vdev_id, peer_addr);
                        if (ret)
-                               ath10k_warn("failed to delete peer %pM on vdev %d: %d\n",
+                               ath10k_warn(ar, "failed to delete peer %pM on vdev %d: %d\n",
                                            peer_addr, vdev_id, ret);
                }
 
@@ -2134,7 +2147,7 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work)
 
                ret = ath10k_wmi_mgmt_tx(ar, skb);
                if (ret) {
-                       ath10k_warn("failed to transmit management frame via WMI: %d\n",
+                       ath10k_warn(ar, "failed to transmit management frame via WMI: %d\n",
                                    ret);
                        ieee80211_free_txskb(ar->hw, skb);
                }
@@ -2145,34 +2158,40 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work)
 /* Scanning */
 /************/
 
-/*
- * This gets called if we dont get a heart-beat during scan.
- * This may indicate the FW has hung and we need to abort the
- * scan manually to prevent cancel_hw_scan() from deadlocking
- */
-void ath10k_reset_scan(unsigned long ptr)
+void __ath10k_scan_finish(struct ath10k *ar)
 {
-       struct ath10k *ar = (struct ath10k *)ptr;
+       lockdep_assert_held(&ar->data_lock);
 
-       spin_lock_bh(&ar->data_lock);
-       if (!ar->scan.in_progress) {
-               spin_unlock_bh(&ar->data_lock);
-               return;
+       switch (ar->scan.state) {
+       case ATH10K_SCAN_IDLE:
+               break;
+       case ATH10K_SCAN_RUNNING:
+       case ATH10K_SCAN_ABORTING:
+               if (ar->scan.is_roc)
+                       ieee80211_remain_on_channel_expired(ar->hw);
+               else
+                       ieee80211_scan_completed(ar->hw,
+                                                (ar->scan.state ==
+                                                 ATH10K_SCAN_ABORTING));
+               /* fall through */
+       case ATH10K_SCAN_STARTING:
+               ar->scan.state = ATH10K_SCAN_IDLE;
+               ar->scan_channel = NULL;
+               ath10k_offchan_tx_purge(ar);
+               cancel_delayed_work(&ar->scan.timeout);
+               complete_all(&ar->scan.completed);
+               break;
        }
+}
 
-       ath10k_warn("scan timed out, firmware problem?\n");
-
-       if (ar->scan.is_roc)
-               ieee80211_remain_on_channel_expired(ar->hw);
-       else
-               ieee80211_scan_completed(ar->hw, 1 /* aborted */);
-
-       ar->scan.in_progress = false;
-       complete_all(&ar->scan.completed);
+void ath10k_scan_finish(struct ath10k *ar)
+{
+       spin_lock_bh(&ar->data_lock);
+       __ath10k_scan_finish(ar);
        spin_unlock_bh(&ar->data_lock);
 }
 
-static int ath10k_abort_scan(struct ath10k *ar)
+static int ath10k_scan_stop(struct ath10k *ar)
 {
        struct wmi_stop_scan_arg arg = {
                .req_id = 1, /* FIXME */
@@ -2183,47 +2202,79 @@ static int ath10k_abort_scan(struct ath10k *ar)
 
        lockdep_assert_held(&ar->conf_mutex);
 
-       del_timer_sync(&ar->scan.timeout);
+       ret = ath10k_wmi_stop_scan(ar, &arg);
+       if (ret) {
+               ath10k_warn(ar, "failed to stop wmi scan: %d\n", ret);
+               goto out;
+       }
 
-       spin_lock_bh(&ar->data_lock);
-       if (!ar->scan.in_progress) {
-               spin_unlock_bh(&ar->data_lock);
-               return 0;
+       ret = wait_for_completion_timeout(&ar->scan.completed, 3*HZ);
+       if (ret == 0) {
+               ath10k_warn(ar, "failed to receive scan abortion completion: timed out\n");
+               ret = -ETIMEDOUT;
+       } else if (ret > 0) {
+               ret = 0;
        }
 
-       ar->scan.aborting = true;
+out:
+       /* Scan state should be updated upon scan completion but in case
+        * firmware fails to deliver the event (for whatever reason) it is
+        * desired to clean up scan state anyway. Firmware may have just
+        * dropped the scan completion event delivery due to transport pipe
+        * being overflown with data and/or it can recover on its own before
+        * next scan request is submitted.
+        */
+       spin_lock_bh(&ar->data_lock);
+       if (ar->scan.state != ATH10K_SCAN_IDLE)
+               __ath10k_scan_finish(ar);
        spin_unlock_bh(&ar->data_lock);
 
-       ret = ath10k_wmi_stop_scan(ar, &arg);
-       if (ret) {
-               ath10k_warn("failed to stop wmi scan: %d\n", ret);
-               spin_lock_bh(&ar->data_lock);
-               ar->scan.in_progress = false;
-               ath10k_offchan_tx_purge(ar);
-               spin_unlock_bh(&ar->data_lock);
-               return -EIO;
-       }
+       return ret;
+}
 
-       ret = wait_for_completion_timeout(&ar->scan.completed, 3*HZ);
-       if (ret == 0)
-               ath10k_warn("timed out while waiting for scan to stop\n");
+static void ath10k_scan_abort(struct ath10k *ar)
+{
+       int ret;
 
-       /* scan completion may be done right after we timeout here, so let's
-        * check the in_progress and tell mac80211 scan is completed. if we
-        * don't do that and FW fails to send us scan completion indication
-        * then userspace won't be able to scan anymore */
-       ret = 0;
+       lockdep_assert_held(&ar->conf_mutex);
 
        spin_lock_bh(&ar->data_lock);
-       if (ar->scan.in_progress) {
-               ath10k_warn("failed to stop scan, it's still in progress\n");
-               ar->scan.in_progress = false;
-               ath10k_offchan_tx_purge(ar);
-               ret = -ETIMEDOUT;
+
+       switch (ar->scan.state) {
+       case ATH10K_SCAN_IDLE:
+               /* This can happen if timeout worker kicked in and called
+                * abortion while scan completion was being processed.
+                */
+               break;
+       case ATH10K_SCAN_STARTING:
+       case ATH10K_SCAN_ABORTING:
+               ath10k_warn(ar, "refusing scan abortion due to invalid scan state: %s (%d)\n",
+                           ath10k_scan_state_str(ar->scan.state),
+                           ar->scan.state);
+               break;
+       case ATH10K_SCAN_RUNNING:
+               ar->scan.state = ATH10K_SCAN_ABORTING;
+               spin_unlock_bh(&ar->data_lock);
+
+               ret = ath10k_scan_stop(ar);
+               if (ret)
+                       ath10k_warn(ar, "failed to abort scan: %d\n", ret);
+
+               spin_lock_bh(&ar->data_lock);
+               break;
        }
+
        spin_unlock_bh(&ar->data_lock);
+}
 
-       return ret;
+void ath10k_scan_timeout_work(struct work_struct *work)
+{
+       struct ath10k *ar = container_of(work, struct ath10k,
+                                        scan.timeout.work);
+
+       mutex_lock(&ar->conf_mutex);
+       ath10k_scan_abort(ar);
+       mutex_unlock(&ar->conf_mutex);
 }
 
 static int ath10k_start_scan(struct ath10k *ar,
@@ -2239,17 +2290,16 @@ static int ath10k_start_scan(struct ath10k *ar,
 
        ret = wait_for_completion_timeout(&ar->scan.started, 1*HZ);
        if (ret == 0) {
-               ath10k_abort_scan(ar);
-               return ret;
+               ret = ath10k_scan_stop(ar);
+               if (ret)
+                       ath10k_warn(ar, "failed to stop scan: %d\n", ret);
+
+               return -ETIMEDOUT;
        }
 
-       /* the scan can complete earlier, before we even
-        * start the timer. in that case the timer handler
-        * checks ar->scan.in_progress and bails out if its
-        * false. Add a 200ms margin to account event/command
-        * processing. */
-       mod_timer(&ar->scan.timeout, jiffies +
-                 msecs_to_jiffies(arg->max_scan_time+200));
+       /* Add a 200ms margin to account for event/command processing */
+       ieee80211_queue_delayed_work(ar->hw, &ar->scan.timeout,
+                                    msecs_to_jiffies(arg->max_scan_time+200));
        return 0;
 }
 
@@ -2269,7 +2319,7 @@ static void ath10k_tx(struct ieee80211_hw *hw,
 
        /* We should disable CCK RATE due to P2P */
        if (info->flags & IEEE80211_TX_CTL_NO_CCK_RATE)
-               ath10k_dbg(ATH10K_DBG_MAC, "IEEE80211_TX_CTL_NO_CCK_RATE\n");
+               ath10k_dbg(ar, ATH10K_DBG_MAC, "IEEE80211_TX_CTL_NO_CCK_RATE\n");
 
        ATH10K_SKB_CB(skb)->htt.is_offchan = false;
        ATH10K_SKB_CB(skb)->htt.tid = ath10k_tx_h_get_tid(hdr);
@@ -2289,7 +2339,8 @@ static void ath10k_tx(struct ieee80211_hw *hw,
                ATH10K_SKB_CB(skb)->vdev_id = ar->scan.vdev_id;
                spin_unlock_bh(&ar->data_lock);
 
-               ath10k_dbg(ATH10K_DBG_MAC, "queued offchannel skb %p\n", skb);
+               ath10k_dbg(ar, ATH10K_DBG_MAC, "queued offchannel skb %p\n",
+                          skb);
 
                skb_queue_tail(&ar->offchan_tx_queue, skb);
                ieee80211_queue_work(hw, &ar->offchan_tx_work);
@@ -2325,8 +2376,7 @@ void ath10k_halt(struct ath10k *ar)
                ath10k_monitor_stop(ar);
        }
 
-       del_timer_sync(&ar->scan.timeout);
-       ath10k_reset_scan((unsigned long)ar);
+       ath10k_scan_finish(ar);
        ath10k_peer_cleanup_all(ar);
        ath10k_core_stop(ar);
        ath10k_hif_power_down(ar);
@@ -2380,7 +2430,7 @@ static int __ath10k_set_antenna(struct ath10k *ar, u32 tx_ant, u32 rx_ant)
        ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->tx_chain_mask,
                                        tx_ant);
        if (ret) {
-               ath10k_warn("failed to set tx-chainmask: %d, req 0x%x\n",
+               ath10k_warn(ar, "failed to set tx-chainmask: %d, req 0x%x\n",
                            ret, tx_ant);
                return ret;
        }
@@ -2388,7 +2438,7 @@ static int __ath10k_set_antenna(struct ath10k *ar, u32 tx_ant, u32 rx_ant)
        ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->rx_chain_mask,
                                        rx_ant);
        if (ret) {
-               ath10k_warn("failed to set rx-chainmask: %d, req 0x%x\n",
+               ath10k_warn(ar, "failed to set rx-chainmask: %d, req 0x%x\n",
                            ret, rx_ant);
                return ret;
        }
@@ -2439,25 +2489,25 @@ static int ath10k_start(struct ieee80211_hw *hw)
 
        ret = ath10k_hif_power_up(ar);
        if (ret) {
-               ath10k_err("Could not init hif: %d\n", ret);
+               ath10k_err(ar, "Could not init hif: %d\n", ret);
                goto err_off;
        }
 
        ret = ath10k_core_start(ar);
        if (ret) {
-               ath10k_err("Could not init core: %d\n", ret);
+               ath10k_err(ar, "Could not init core: %d\n", ret);
                goto err_power_down;
        }
 
        ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->pmf_qos, 1);
        if (ret) {
-               ath10k_warn("failed to enable PMF QOS: %d\n", ret);
+               ath10k_warn(ar, "failed to enable PMF QOS: %d\n", ret);
                goto err_core_stop;
        }
 
        ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->dynamic_bw, 1);
        if (ret) {
-               ath10k_warn("failed to enable dynamic BW: %d\n", ret);
+               ath10k_warn(ar, "failed to enable dynamic BW: %d\n", ret);
                goto err_core_stop;
        }
 
@@ -2477,7 +2527,7 @@ static int ath10k_start(struct ieee80211_hw *hw)
        ret = ath10k_wmi_pdev_set_param(ar,
                                        ar->wmi.pdev_param->arp_ac_override, 0);
        if (ret) {
-               ath10k_warn("failed to set arp ac override parameter: %d\n",
+               ath10k_warn(ar, "failed to set arp ac override parameter: %d\n",
                            ret);
                goto err_core_stop;
        }
@@ -2485,6 +2535,8 @@ static int ath10k_start(struct ieee80211_hw *hw)
        ar->num_started_vdevs = 0;
        ath10k_regd_update(ar);
 
+       ath10k_spectral_start(ar);
+
        mutex_unlock(&ar->conf_mutex);
        return 0;
 
@@ -2515,6 +2567,7 @@ static void ath10k_stop(struct ieee80211_hw *hw)
        }
        mutex_unlock(&ar->conf_mutex);
 
+       cancel_delayed_work_sync(&ar->scan.timeout);
        cancel_work_sync(&ar->restart_work);
 }
 
@@ -2528,7 +2581,7 @@ static int ath10k_config_ps(struct ath10k *ar)
        list_for_each_entry(arvif, &ar->arvifs, list) {
                ret = ath10k_mac_vif_setup_ps(arvif);
                if (ret) {
-                       ath10k_warn("failed to setup powersave: %d\n", ret);
+                       ath10k_warn(ar, "failed to setup powersave: %d\n", ret);
                        break;
                }
        }
@@ -2566,7 +2619,7 @@ static void ath10k_config_chan(struct ath10k *ar)
 
        lockdep_assert_held(&ar->conf_mutex);
 
-       ath10k_dbg(ATH10K_DBG_MAC,
+       ath10k_dbg(ar, ATH10K_DBG_MAC,
                   "mac config channel to %dMHz (cf1 %dMHz cf2 %dMHz width %s)\n",
                   ar->chandef.chan->center_freq,
                   ar->chandef.center_freq1,
@@ -2582,18 +2635,21 @@ static void ath10k_config_chan(struct ath10k *ar)
                if (!arvif->is_started)
                        continue;
 
+               if (!arvif->is_up)
+                       continue;
+
                if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)
                        continue;
 
-               ret = ath10k_vdev_stop(arvif);
+               ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
                if (ret) {
-                       ath10k_warn("failed to stop vdev %d: %d\n",
+                       ath10k_warn(ar, "failed to down vdev %d: %d\n",
                                    arvif->vdev_id, ret);
                        continue;
                }
        }
 
-       /* all vdevs are now stopped - now attempt to restart them */
+       /* all vdevs are downed now - attempt to restart and re-up them */
 
        list_for_each_entry(arvif, &ar->arvifs, list) {
                if (!arvif->is_started)
@@ -2602,9 +2658,9 @@ static void ath10k_config_chan(struct ath10k *ar)
                if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)
                        continue;
 
-               ret = ath10k_vdev_start(arvif);
+               ret = ath10k_vdev_restart(arvif);
                if (ret) {
-                       ath10k_warn("failed to start vdev %d: %d\n",
+                       ath10k_warn(ar, "failed to restart vdev %d: %d\n",
                                    arvif->vdev_id, ret);
                        continue;
                }
@@ -2615,7 +2671,7 @@ static void ath10k_config_chan(struct ath10k *ar)
                ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
                                         arvif->bssid);
                if (ret) {
-                       ath10k_warn("failed to bring vdev up %d: %d\n",
+                       ath10k_warn(ar, "failed to bring vdev up %d: %d\n",
                                    arvif->vdev_id, ret);
                        continue;
                }
@@ -2635,7 +2691,7 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
        mutex_lock(&ar->conf_mutex);
 
        if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
-               ath10k_dbg(ATH10K_DBG_MAC,
+               ath10k_dbg(ar, ATH10K_DBG_MAC,
                           "mac config channel %dMHz flags 0x%x radar %d\n",
                           conf->chandef.chan->center_freq,
                           conf->chandef.chan->flags,
@@ -2655,21 +2711,21 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
        }
 
        if (changed & IEEE80211_CONF_CHANGE_POWER) {
-               ath10k_dbg(ATH10K_DBG_MAC, "mac config power %d\n",
+               ath10k_dbg(ar, ATH10K_DBG_MAC, "mac config power %d\n",
                           hw->conf.power_level);
 
                param = ar->wmi.pdev_param->txpower_limit2g;
                ret = ath10k_wmi_pdev_set_param(ar, param,
                                                hw->conf.power_level * 2);
                if (ret)
-                       ath10k_warn("failed to set 2g txpower %d: %d\n",
+                       ath10k_warn(ar, "failed to set 2g txpower %d: %d\n",
                                    hw->conf.power_level, ret);
 
                param = ar->wmi.pdev_param->txpower_limit5g;
                ret = ath10k_wmi_pdev_set_param(ar, param,
                                                hw->conf.power_level * 2);
                if (ret)
-                       ath10k_warn("failed to set 5g txpower %d: %d\n",
+                       ath10k_warn(ar, "failed to set 5g txpower %d: %d\n",
                                    hw->conf.power_level, ret);
        }
 
@@ -2681,7 +2737,7 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
                        ar->monitor = true;
                        ret = ath10k_monitor_start(ar);
                        if (ret) {
-                               ath10k_warn("failed to start monitor (config): %d\n",
+                               ath10k_warn(ar, "failed to start monitor (config): %d\n",
                                            ret);
                                ar->monitor = false;
                        }
@@ -2724,11 +2780,12 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
        INIT_WORK(&arvif->wep_key_work, ath10k_tx_wep_key_work);
        INIT_LIST_HEAD(&arvif->list);
 
-       bit = ffs(ar->free_vdev_map);
-       if (bit == 0) {
+       if (ar->free_vdev_map == 0) {
+               ath10k_warn(ar, "Free vdev map is empty, no more interfaces allowed.\n");
                ret = -EBUSY;
                goto err;
        }
+       bit = ffs(ar->free_vdev_map);
 
        arvif->vdev_id = bit - 1;
        arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE;
@@ -2760,25 +2817,25 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
                break;
        }
 
-       ath10k_dbg(ATH10K_DBG_MAC, "mac vdev create %d (add interface) type %d subtype %d\n",
+       ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev create %d (add interface) type %d subtype %d\n",
                   arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype);
 
        ret = ath10k_wmi_vdev_create(ar, arvif->vdev_id, arvif->vdev_type,
                                     arvif->vdev_subtype, vif->addr);
        if (ret) {
-               ath10k_warn("failed to create WMI vdev %i: %d\n",
+               ath10k_warn(ar, "failed to create WMI vdev %i: %d\n",
                            arvif->vdev_id, ret);
                goto err;
        }
 
-       ar->free_vdev_map &= ~BIT(arvif->vdev_id);
+       ar->free_vdev_map &= ~(1 << arvif->vdev_id);
        list_add(&arvif->list, &ar->arvifs);
 
        vdev_param = ar->wmi.vdev_param->def_keyid;
        ret = ath10k_wmi_vdev_set_param(ar, 0, vdev_param,
                                        arvif->def_wep_key_idx);
        if (ret) {
-               ath10k_warn("failed to set vdev %i default key id: %d\n",
+               ath10k_warn(ar, "failed to set vdev %i default key id: %d\n",
                            arvif->vdev_id, ret);
                goto err_vdev_delete;
        }
@@ -2788,7 +2845,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
                                        ATH10K_HW_TXRX_NATIVE_WIFI);
        /* 10.X firmware does not support this VDEV parameter. Do not warn */
        if (ret && ret != -EOPNOTSUPP) {
-               ath10k_warn("failed to set vdev %i TX encapsulation: %d\n",
+               ath10k_warn(ar, "failed to set vdev %i TX encapsulation: %d\n",
                            arvif->vdev_id, ret);
                goto err_vdev_delete;
        }
@@ -2796,14 +2853,14 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
        if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
                ret = ath10k_peer_create(ar, arvif->vdev_id, vif->addr);
                if (ret) {
-                       ath10k_warn("failed to create vdev %i peer for AP: %d\n",
+                       ath10k_warn(ar, "failed to create vdev %i peer for AP: %d\n",
                                    arvif->vdev_id, ret);
                        goto err_vdev_delete;
                }
 
                ret = ath10k_mac_set_kickout(arvif);
                if (ret) {
-                       ath10k_warn("failed to set vdev %i kickout parameters: %d\n",
+                       ath10k_warn(ar, "failed to set vdev %i kickout parameters: %d\n",
                                    arvif->vdev_id, ret);
                        goto err_peer_delete;
                }
@@ -2815,7 +2872,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
                ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
                                                  param, value);
                if (ret) {
-                       ath10k_warn("failed to set vdev %i RX wake policy: %d\n",
+                       ath10k_warn(ar, "failed to set vdev %i RX wake policy: %d\n",
                                    arvif->vdev_id, ret);
                        goto err_peer_delete;
                }
@@ -2825,7 +2882,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
                ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
                                                  param, value);
                if (ret) {
-                       ath10k_warn("failed to set vdev %i TX wake thresh: %d\n",
+                       ath10k_warn(ar, "failed to set vdev %i TX wake thresh: %d\n",
                                    arvif->vdev_id, ret);
                        goto err_peer_delete;
                }
@@ -2835,7 +2892,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
                ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
                                                  param, value);
                if (ret) {
-                       ath10k_warn("failed to set vdev %i PSPOLL count: %d\n",
+                       ath10k_warn(ar, "failed to set vdev %i PSPOLL count: %d\n",
                                    arvif->vdev_id, ret);
                        goto err_peer_delete;
                }
@@ -2843,14 +2900,14 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
 
        ret = ath10k_mac_set_rts(arvif, ar->hw->wiphy->rts_threshold);
        if (ret) {
-               ath10k_warn("failed to set rts threshold for vdev %d: %d\n",
+               ath10k_warn(ar, "failed to set rts threshold for vdev %d: %d\n",
                            arvif->vdev_id, ret);
                goto err_peer_delete;
        }
 
        ret = ath10k_mac_set_frag(arvif, ar->hw->wiphy->frag_threshold);
        if (ret) {
-               ath10k_warn("failed to set frag threshold for vdev %d: %d\n",
+               ath10k_warn(ar, "failed to set frag threshold for vdev %d: %d\n",
                            arvif->vdev_id, ret);
                goto err_peer_delete;
        }
@@ -2864,7 +2921,7 @@ err_peer_delete:
 
 err_vdev_delete:
        ath10k_wmi_vdev_delete(ar, arvif->vdev_id);
-       ar->free_vdev_map &= ~BIT(arvif->vdev_id);
+       ar->free_vdev_map |= 1 << arvif->vdev_id;
        list_del(&arvif->list);
 
 err:
@@ -2892,26 +2949,32 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
                dev_kfree_skb_any(arvif->beacon);
                arvif->beacon = NULL;
        }
+
        spin_unlock_bh(&ar->data_lock);
 
-       ar->free_vdev_map |= 1 << (arvif->vdev_id);
+       ret = ath10k_spectral_vif_stop(arvif);
+       if (ret)
+               ath10k_warn(ar, "failed to stop spectral for vdev %i: %d\n",
+                           arvif->vdev_id, ret);
+
+       ar->free_vdev_map |= 1 << arvif->vdev_id;
        list_del(&arvif->list);
 
        if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
                ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, vif->addr);
                if (ret)
-                       ath10k_warn("failed to remove peer for AP vdev %i: %d\n",
+                       ath10k_warn(ar, "failed to remove peer for AP vdev %i: %d\n",
                                    arvif->vdev_id, ret);
 
                kfree(arvif->u.ap.noa_data);
        }
 
-       ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %i delete (remove interface)\n",
+       ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %i delete (remove interface)\n",
                   arvif->vdev_id);
 
        ret = ath10k_wmi_vdev_delete(ar, arvif->vdev_id);
        if (ret)
-               ath10k_warn("failed to delete WMI vdev %i: %d\n",
+               ath10k_warn(ar, "failed to delete WMI vdev %i: %d\n",
                            arvif->vdev_id, ret);
 
        ath10k_peer_cleanup(ar, arvif->vdev_id);
@@ -2950,7 +3013,7 @@ static void ath10k_configure_filter(struct ieee80211_hw *hw,
                ar->promisc = true;
                ret = ath10k_monitor_start(ar);
                if (ret) {
-                       ath10k_warn("failed to start monitor (promisc): %d\n",
+                       ath10k_warn(ar, "failed to start monitor (promisc): %d\n",
                                    ret);
                        ar->promisc = false;
                }
@@ -2982,17 +3045,17 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
                vdev_param = ar->wmi.vdev_param->beacon_interval;
                ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
                                                arvif->beacon_interval);
-               ath10k_dbg(ATH10K_DBG_MAC,
+               ath10k_dbg(ar, ATH10K_DBG_MAC,
                           "mac vdev %d beacon_interval %d\n",
                           arvif->vdev_id, arvif->beacon_interval);
 
                if (ret)
-                       ath10k_warn("failed to set beacon interval for vdev %d: %i\n",
+                       ath10k_warn(ar, "failed to set beacon interval for vdev %d: %i\n",
                                    arvif->vdev_id, ret);
        }
 
        if (changed & BSS_CHANGED_BEACON) {
-               ath10k_dbg(ATH10K_DBG_MAC,
+               ath10k_dbg(ar, ATH10K_DBG_MAC,
                           "vdev %d set beacon tx mode to staggered\n",
                           arvif->vdev_id);
 
@@ -3000,14 +3063,14 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
                ret = ath10k_wmi_pdev_set_param(ar, pdev_param,
                                                WMI_BEACON_STAGGERED_MODE);
                if (ret)
-                       ath10k_warn("failed to set beacon mode for vdev %d: %i\n",
+                       ath10k_warn(ar, "failed to set beacon mode for vdev %d: %i\n",
                                    arvif->vdev_id, ret);
        }
 
        if (changed & BSS_CHANGED_BEACON_INFO) {
                arvif->dtim_period = info->dtim_period;
 
-               ath10k_dbg(ATH10K_DBG_MAC,
+               ath10k_dbg(ar, ATH10K_DBG_MAC,
                           "mac vdev %d dtim_period %d\n",
                           arvif->vdev_id, arvif->dtim_period);
 
@@ -3015,7 +3078,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
                ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
                                                arvif->dtim_period);
                if (ret)
-                       ath10k_warn("failed to set dtim period for vdev %d: %i\n",
+                       ath10k_warn(ar, "failed to set dtim period for vdev %d: %i\n",
                                    arvif->vdev_id, ret);
        }
 
@@ -3034,14 +3097,14 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
        if (changed & BSS_CHANGED_BSSID &&
            vif->type != NL80211_IFTYPE_AP) {
                if (!is_zero_ether_addr(info->bssid)) {
-                       ath10k_dbg(ATH10K_DBG_MAC,
+                       ath10k_dbg(ar, ATH10K_DBG_MAC,
                                   "mac vdev %d create peer %pM\n",
                                   arvif->vdev_id, info->bssid);
 
                        ret = ath10k_peer_create(ar, arvif->vdev_id,
                                                 info->bssid);
                        if (ret)
-                               ath10k_warn("failed to add peer %pM for vdev %d when changing bssid: %i\n",
+                               ath10k_warn(ar, "failed to add peer %pM for vdev %d when changing bssid: %i\n",
                                            info->bssid, arvif->vdev_id, ret);
 
                        if (vif->type == NL80211_IFTYPE_STATION) {
@@ -3051,13 +3114,13 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
                                 */
                                memcpy(arvif->bssid, info->bssid, ETH_ALEN);
 
-                               ath10k_dbg(ATH10K_DBG_MAC,
+                               ath10k_dbg(ar, ATH10K_DBG_MAC,
                                           "mac vdev %d start %pM\n",
                                           arvif->vdev_id, info->bssid);
 
                                ret = ath10k_vdev_start(arvif);
                                if (ret) {
-                                       ath10k_warn("failed to start vdev %i: %d\n",
+                                       ath10k_warn(ar, "failed to start vdev %i: %d\n",
                                                    arvif->vdev_id, ret);
                                        goto exit;
                                }
@@ -3081,12 +3144,12 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
 
        if (changed & BSS_CHANGED_ERP_CTS_PROT) {
                arvif->use_cts_prot = info->use_cts_prot;
-               ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d cts_prot %d\n",
+               ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d cts_prot %d\n",
                           arvif->vdev_id, info->use_cts_prot);
 
                ret = ath10k_recalc_rtscts_prot(arvif);
                if (ret)
-                       ath10k_warn("failed to recalculate rts/cts prot for vdev %d: %d\n",
+                       ath10k_warn(ar, "failed to recalculate rts/cts prot for vdev %d: %d\n",
                                    arvif->vdev_id, ret);
        }
 
@@ -3098,14 +3161,14 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
                else
                        slottime = WMI_VDEV_SLOT_TIME_LONG; /* 20us */
 
-               ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d slot_time %d\n",
+               ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d slot_time %d\n",
                           arvif->vdev_id, slottime);
 
                vdev_param = ar->wmi.vdev_param->slot_time;
                ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
                                                slottime);
                if (ret)
-                       ath10k_warn("failed to set erp slot for vdev %d: %i\n",
+                       ath10k_warn(ar, "failed to set erp slot for vdev %d: %i\n",
                                    arvif->vdev_id, ret);
        }
 
@@ -3116,7 +3179,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
                else
                        preamble = WMI_VDEV_PREAMBLE_LONG;
 
-               ath10k_dbg(ATH10K_DBG_MAC,
+               ath10k_dbg(ar, ATH10K_DBG_MAC,
                           "mac vdev %d preamble %dn",
                           arvif->vdev_id, preamble);
 
@@ -3124,7 +3187,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
                ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
                                                preamble);
                if (ret)
-                       ath10k_warn("failed to set preamble for vdev %d: %i\n",
+                       ath10k_warn(ar, "failed to set preamble for vdev %d: %i\n",
                                    arvif->vdev_id, ret);
        }
 
@@ -3151,20 +3214,26 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw,
        mutex_lock(&ar->conf_mutex);
 
        spin_lock_bh(&ar->data_lock);
-       if (ar->scan.in_progress) {
-               spin_unlock_bh(&ar->data_lock);
+       switch (ar->scan.state) {
+       case ATH10K_SCAN_IDLE:
+               reinit_completion(&ar->scan.started);
+               reinit_completion(&ar->scan.completed);
+               ar->scan.state = ATH10K_SCAN_STARTING;
+               ar->scan.is_roc = false;
+               ar->scan.vdev_id = arvif->vdev_id;
+               ret = 0;
+               break;
+       case ATH10K_SCAN_STARTING:
+       case ATH10K_SCAN_RUNNING:
+       case ATH10K_SCAN_ABORTING:
                ret = -EBUSY;
-               goto exit;
+               break;
        }
-
-       reinit_completion(&ar->scan.started);
-       reinit_completion(&ar->scan.completed);
-       ar->scan.in_progress = true;
-       ar->scan.aborting = false;
-       ar->scan.is_roc = false;
-       ar->scan.vdev_id = arvif->vdev_id;
        spin_unlock_bh(&ar->data_lock);
 
+       if (ret)
+               goto exit;
+
        memset(&arg, 0, sizeof(arg));
        ath10k_wmi_start_scan_init(ar, &arg);
        arg.vdev_id = arvif->vdev_id;
@@ -3196,9 +3265,9 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw,
 
        ret = ath10k_start_scan(ar, &arg);
        if (ret) {
-               ath10k_warn("failed to start hw scan: %d\n", ret);
+               ath10k_warn(ar, "failed to start hw scan: %d\n", ret);
                spin_lock_bh(&ar->data_lock);
-               ar->scan.in_progress = false;
+               ar->scan.state = ATH10K_SCAN_IDLE;
                spin_unlock_bh(&ar->data_lock);
        }
 
@@ -3211,14 +3280,10 @@ static void ath10k_cancel_hw_scan(struct ieee80211_hw *hw,
                                  struct ieee80211_vif *vif)
 {
        struct ath10k *ar = hw->priv;
-       int ret;
 
        mutex_lock(&ar->conf_mutex);
-       ret = ath10k_abort_scan(ar);
-       if (ret) {
-               ath10k_warn("failed to abort scan: %d\n", ret);
-               ieee80211_scan_completed(hw, 1 /* aborted */);
-       }
+       cancel_delayed_work_sync(&ar->scan.timeout);
+       ath10k_scan_abort(ar);
        mutex_unlock(&ar->conf_mutex);
 }
 
@@ -3256,7 +3321,7 @@ static void ath10k_set_key_h_def_keyidx(struct ath10k *ar,
        ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
                                        key->keyidx);
        if (ret)
-               ath10k_warn("failed to set vdev %i group key as default key: %d\n",
+               ath10k_warn(ar, "failed to set vdev %i group key as default key: %d\n",
                            arvif->vdev_id, ret);
 }
 
@@ -3294,7 +3359,7 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 
        if (!peer) {
                if (cmd == SET_KEY) {
-                       ath10k_warn("failed to install key for non-existent peer %pM\n",
+                       ath10k_warn(ar, "failed to install key for non-existent peer %pM\n",
                                    peer_addr);
                        ret = -EOPNOTSUPP;
                        goto exit;
@@ -3317,7 +3382,7 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 
        ret = ath10k_install_key(arvif, key, cmd, peer_addr);
        if (ret) {
-               ath10k_warn("failed to install key for vdev %i peer %pM: %d\n",
+               ath10k_warn(ar, "failed to install key for vdev %i peer %pM: %d\n",
                            arvif->vdev_id, peer_addr, ret);
                goto exit;
        }
@@ -3332,7 +3397,7 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                peer->keys[key->keyidx] = NULL;
        else if (peer == NULL)
                /* impossible unless FW goes crazy */
-               ath10k_warn("Peer %pM disappeared!\n", peer_addr);
+               ath10k_warn(ar, "Peer %pM disappeared!\n", peer_addr);
        spin_unlock_bh(&ar->data_lock);
 
 exit:
@@ -3368,45 +3433,45 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk)
        mutex_lock(&ar->conf_mutex);
 
        if (changed & IEEE80211_RC_BW_CHANGED) {
-               ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM peer bw %d\n",
+               ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM peer bw %d\n",
                           sta->addr, bw);
 
                err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
                                                WMI_PEER_CHAN_WIDTH, bw);
                if (err)
-                       ath10k_warn("failed to update STA %pM peer bw %d: %d\n",
+                       ath10k_warn(ar, "failed to update STA %pM peer bw %d: %d\n",
                                    sta->addr, bw, err);
        }
 
        if (changed & IEEE80211_RC_NSS_CHANGED) {
-               ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM nss %d\n",
+               ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM nss %d\n",
                           sta->addr, nss);
 
                err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
                                                WMI_PEER_NSS, nss);
                if (err)
-                       ath10k_warn("failed to update STA %pM nss %d: %d\n",
+                       ath10k_warn(ar, "failed to update STA %pM nss %d: %d\n",
                                    sta->addr, nss, err);
        }
 
        if (changed & IEEE80211_RC_SMPS_CHANGED) {
-               ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM smps %d\n",
+               ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM smps %d\n",
                           sta->addr, smps);
 
                err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
                                                WMI_PEER_SMPS_STATE, smps);
                if (err)
-                       ath10k_warn("failed to update STA %pM smps %d: %d\n",
+                       ath10k_warn(ar, "failed to update STA %pM smps %d: %d\n",
                                    sta->addr, smps, err);
        }
 
        if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) {
-               ath10k_dbg(ATH10K_DBG_MAC, "mac update sta %pM supp rates\n",
+               ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates\n",
                           sta->addr);
 
                err = ath10k_station_assoc(ar, arvif, sta, true);
                if (err)
-                       ath10k_warn("failed to reassociate station: %pM\n",
+                       ath10k_warn(ar, "failed to reassociate station: %pM\n",
                                    sta->addr);
        }
 
@@ -3451,31 +3516,31 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
                        max_num_peers = TARGET_NUM_PEERS;
 
                if (ar->num_peers >= max_num_peers) {
-                       ath10k_warn("number of peers exceeded: peers number %d (max peers %d)\n",
+                       ath10k_warn(ar, "number of peers exceeded: peers number %d (max peers %d)\n",
                                    ar->num_peers, max_num_peers);
                        ret = -ENOBUFS;
                        goto exit;
                }
 
-               ath10k_dbg(ATH10K_DBG_MAC,
+               ath10k_dbg(ar, ATH10K_DBG_MAC,
                           "mac vdev %d peer create %pM (new sta) num_peers %d\n",
                           arvif->vdev_id, sta->addr, ar->num_peers);
 
                ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr);
                if (ret)
-                       ath10k_warn("failed to add peer %pM for vdev %d when adding a new sta: %i\n",
+                       ath10k_warn(ar, "failed to add peer %pM for vdev %d when adding a new sta: %i\n",
                                    sta->addr, arvif->vdev_id, ret);
        } else if ((old_state == IEEE80211_STA_NONE &&
                    new_state == IEEE80211_STA_NOTEXIST)) {
                /*
                 * Existing station deletion.
                 */
-               ath10k_dbg(ATH10K_DBG_MAC,
+               ath10k_dbg(ar, ATH10K_DBG_MAC,
                           "mac vdev %d peer delete %pM (sta gone)\n",
                           arvif->vdev_id, sta->addr);
                ret = ath10k_peer_delete(ar, arvif->vdev_id, sta->addr);
                if (ret)
-                       ath10k_warn("failed to delete peer %pM for vdev %d: %i\n",
+                       ath10k_warn(ar, "failed to delete peer %pM for vdev %d: %i\n",
                                    sta->addr, arvif->vdev_id, ret);
 
                if (vif->type == NL80211_IFTYPE_STATION)
@@ -3487,12 +3552,12 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
                /*
                 * New association.
                 */
-               ath10k_dbg(ATH10K_DBG_MAC, "mac sta %pM associated\n",
+               ath10k_dbg(ar, ATH10K_DBG_MAC, "mac sta %pM associated\n",
                           sta->addr);
 
                ret = ath10k_station_assoc(ar, arvif, sta, false);
                if (ret)
-                       ath10k_warn("failed to associate station %pM for vdev %i: %i\n",
+                       ath10k_warn(ar, "failed to associate station %pM for vdev %i: %i\n",
                                    sta->addr, arvif->vdev_id, ret);
        } else if (old_state == IEEE80211_STA_ASSOC &&
                   new_state == IEEE80211_STA_AUTH &&
@@ -3501,12 +3566,12 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
                /*
                 * Disassociation.
                 */
-               ath10k_dbg(ATH10K_DBG_MAC, "mac sta %pM disassociated\n",
+               ath10k_dbg(ar, ATH10K_DBG_MAC, "mac sta %pM disassociated\n",
                           sta->addr);
 
                ret = ath10k_station_disassoc(ar, arvif, sta);
                if (ret)
-                       ath10k_warn("failed to disassociate station: %pM vdev %i: %i\n",
+                       ath10k_warn(ar, "failed to disassociate station: %pM vdev %i: %i\n",
                                    sta->addr, arvif->vdev_id, ret);
        }
 exit:
@@ -3554,7 +3619,7 @@ static int ath10k_conf_tx_uapsd(struct ath10k *ar, struct ieee80211_vif *vif,
                                          WMI_STA_PS_PARAM_UAPSD,
                                          arvif->u.sta.uapsd);
        if (ret) {
-               ath10k_warn("failed to set uapsd params: %d\n", ret);
+               ath10k_warn(ar, "failed to set uapsd params: %d\n", ret);
                goto exit;
        }
 
@@ -3567,7 +3632,7 @@ static int ath10k_conf_tx_uapsd(struct ath10k *ar, struct ieee80211_vif *vif,
                                          WMI_STA_PS_PARAM_RX_WAKE_POLICY,
                                          value);
        if (ret)
-               ath10k_warn("failed to set rx wake param: %d\n", ret);
+               ath10k_warn(ar, "failed to set rx wake param: %d\n", ret);
 
 exit:
        return ret;
@@ -3617,13 +3682,13 @@ static int ath10k_conf_tx(struct ieee80211_hw *hw,
        /* FIXME: FW accepts wmm params per hw, not per vif */
        ret = ath10k_wmi_pdev_set_wmm_params(ar, &ar->wmm_params);
        if (ret) {
-               ath10k_warn("failed to set wmm params: %d\n", ret);
+               ath10k_warn(ar, "failed to set wmm params: %d\n", ret);
                goto exit;
        }
 
        ret = ath10k_conf_tx_uapsd(ar, vif, ac, params->uapsd);
        if (ret)
-               ath10k_warn("failed to set sta uapsd: %d\n", ret);
+               ath10k_warn(ar, "failed to set sta uapsd: %d\n", ret);
 
 exit:
        mutex_unlock(&ar->conf_mutex);
@@ -3641,27 +3706,33 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw,
        struct ath10k *ar = hw->priv;
        struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
        struct wmi_start_scan_arg arg;
-       int ret;
+       int ret = 0;
 
        mutex_lock(&ar->conf_mutex);
 
        spin_lock_bh(&ar->data_lock);
-       if (ar->scan.in_progress) {
-               spin_unlock_bh(&ar->data_lock);
+       switch (ar->scan.state) {
+       case ATH10K_SCAN_IDLE:
+               reinit_completion(&ar->scan.started);
+               reinit_completion(&ar->scan.completed);
+               reinit_completion(&ar->scan.on_channel);
+               ar->scan.state = ATH10K_SCAN_STARTING;
+               ar->scan.is_roc = true;
+               ar->scan.vdev_id = arvif->vdev_id;
+               ar->scan.roc_freq = chan->center_freq;
+               ret = 0;
+               break;
+       case ATH10K_SCAN_STARTING:
+       case ATH10K_SCAN_RUNNING:
+       case ATH10K_SCAN_ABORTING:
                ret = -EBUSY;
-               goto exit;
+               break;
        }
-
-       reinit_completion(&ar->scan.started);
-       reinit_completion(&ar->scan.completed);
-       reinit_completion(&ar->scan.on_channel);
-       ar->scan.in_progress = true;
-       ar->scan.aborting = false;
-       ar->scan.is_roc = true;
-       ar->scan.vdev_id = arvif->vdev_id;
-       ar->scan.roc_freq = chan->center_freq;
        spin_unlock_bh(&ar->data_lock);
 
+       if (ret)
+               goto exit;
+
        memset(&arg, 0, sizeof(arg));
        ath10k_wmi_start_scan_init(ar, &arg);
        arg.vdev_id = arvif->vdev_id;
@@ -3676,17 +3747,21 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw,
 
        ret = ath10k_start_scan(ar, &arg);
        if (ret) {
-               ath10k_warn("failed to start roc scan: %d\n", ret);
+               ath10k_warn(ar, "failed to start roc scan: %d\n", ret);
                spin_lock_bh(&ar->data_lock);
-               ar->scan.in_progress = false;
+               ar->scan.state = ATH10K_SCAN_IDLE;
                spin_unlock_bh(&ar->data_lock);
                goto exit;
        }
 
        ret = wait_for_completion_timeout(&ar->scan.on_channel, 3*HZ);
        if (ret == 0) {
-               ath10k_warn("failed to switch to channel for roc scan\n");
-               ath10k_abort_scan(ar);
+               ath10k_warn(ar, "failed to switch to channel for roc scan\n");
+
+               ret = ath10k_scan_stop(ar);
+               if (ret)
+                       ath10k_warn(ar, "failed to stop scan: %d\n", ret);
+
                ret = -ETIMEDOUT;
                goto exit;
        }
@@ -3702,7 +3777,8 @@ static int ath10k_cancel_remain_on_channel(struct ieee80211_hw *hw)
        struct ath10k *ar = hw->priv;
 
        mutex_lock(&ar->conf_mutex);
-       ath10k_abort_scan(ar);
+       cancel_delayed_work_sync(&ar->scan.timeout);
+       ath10k_scan_abort(ar);
        mutex_unlock(&ar->conf_mutex);
 
        return 0;
@@ -3721,12 +3797,12 @@ static int ath10k_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
 
        mutex_lock(&ar->conf_mutex);
        list_for_each_entry(arvif, &ar->arvifs, list) {
-               ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d rts threshold %d\n",
+               ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d rts threshold %d\n",
                           arvif->vdev_id, value);
 
                ret = ath10k_mac_set_rts(arvif, value);
                if (ret) {
-                       ath10k_warn("failed to set rts threshold for vdev %d: %d\n",
+                       ath10k_warn(ar, "failed to set rts threshold for vdev %d: %d\n",
                                    arvif->vdev_id, ret);
                        break;
                }
@@ -3744,12 +3820,12 @@ static int ath10k_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
 
        mutex_lock(&ar->conf_mutex);
        list_for_each_entry(arvif, &ar->arvifs, list) {
-               ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d fragmentation threshold %d\n",
+               ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d fragmentation threshold %d\n",
                           arvif->vdev_id, value);
 
                ret = ath10k_mac_set_rts(arvif, value);
                if (ret) {
-                       ath10k_warn("failed to set fragmentation threshold for vdev %d: %d\n",
+                       ath10k_warn(ar, "failed to set fragmentation threshold for vdev %d: %d\n",
                                    arvif->vdev_id, ret);
                        break;
                }
@@ -3789,7 +3865,7 @@ static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                }), ATH10K_FLUSH_TIMEOUT_HZ);
 
        if (ret <= 0 || skip)
-               ath10k_warn("failed to flush transmit queue (skip %i ar-state %i): %i\n",
+               ath10k_warn(ar, "failed to flush transmit queue (skip %i ar-state %i): %i\n",
                            skip, ar->state, ret);
 
 skip:
@@ -3824,7 +3900,7 @@ static int ath10k_suspend(struct ieee80211_hw *hw,
 
        ret = ath10k_hif_suspend(ar);
        if (ret) {
-               ath10k_warn("failed to suspend hif: %d\n", ret);
+               ath10k_warn(ar, "failed to suspend hif: %d\n", ret);
                goto resume;
        }
 
@@ -3833,7 +3909,7 @@ static int ath10k_suspend(struct ieee80211_hw *hw,
 resume:
        ret = ath10k_wmi_pdev_resume_target(ar);
        if (ret)
-               ath10k_warn("failed to resume target: %d\n", ret);
+               ath10k_warn(ar, "failed to resume target: %d\n", ret);
 
        ret = 1;
 exit:
@@ -3850,14 +3926,14 @@ static int ath10k_resume(struct ieee80211_hw *hw)
 
        ret = ath10k_hif_resume(ar);
        if (ret) {
-               ath10k_warn("failed to resume hif: %d\n", ret);
+               ath10k_warn(ar, "failed to resume hif: %d\n", ret);
                ret = 1;
                goto exit;
        }
 
        ret = ath10k_wmi_pdev_resume_target(ar);
        if (ret) {
-               ath10k_warn("failed to resume target: %d\n", ret);
+               ath10k_warn(ar, "failed to resume target: %d\n", ret);
                ret = 1;
                goto exit;
        }
@@ -3878,7 +3954,7 @@ static void ath10k_restart_complete(struct ieee80211_hw *hw)
        /* If device failed to restart it will be in a different state, e.g.
         * ATH10K_STATE_WEDGED */
        if (ar->state == ATH10K_STATE_RESTARTED) {
-               ath10k_info("device successfully recovered\n");
+               ath10k_info(ar, "device successfully recovered\n");
                ar->state = ATH10K_STATE_ON;
        }
 
@@ -4075,7 +4151,8 @@ ath10k_bitrate_mask_correct(const struct cfg80211_bitrate_mask *mask,
 }
 
 static bool
-ath10k_bitrate_mask_rate(const struct cfg80211_bitrate_mask *mask,
+ath10k_bitrate_mask_rate(struct ath10k *ar,
+                        const struct cfg80211_bitrate_mask *mask,
                         enum ieee80211_band band,
                         u8 *fixed_rate,
                         u8 *fixed_nss)
@@ -4133,7 +4210,7 @@ ath10k_bitrate_mask_rate(const struct cfg80211_bitrate_mask *mask,
        nss <<= 4;
        pream <<= 6;
 
-       ath10k_dbg(ATH10K_DBG_MAC, "mac fixed rate pream 0x%02x nss 0x%02x rate 0x%02x\n",
+       ath10k_dbg(ar, ATH10K_DBG_MAC, "mac fixed rate pream 0x%02x nss 0x%02x rate 0x%02x\n",
                   pream, nss, rate);
 
        *fixed_rate = pream | nss | rate;
@@ -4141,7 +4218,8 @@ ath10k_bitrate_mask_rate(const struct cfg80211_bitrate_mask *mask,
        return true;
 }
 
-static bool ath10k_get_fixed_rate_nss(const struct cfg80211_bitrate_mask *mask,
+static bool ath10k_get_fixed_rate_nss(struct ath10k *ar,
+                                     const struct cfg80211_bitrate_mask *mask,
                                      enum ieee80211_band band,
                                      u8 *fixed_rate,
                                      u8 *fixed_nss)
@@ -4151,7 +4229,7 @@ static bool ath10k_get_fixed_rate_nss(const struct cfg80211_bitrate_mask *mask,
                return true;
 
        /* Next Check single rate is set */
-       return ath10k_bitrate_mask_rate(mask, band, fixed_rate, fixed_nss);
+       return ath10k_bitrate_mask_rate(ar, mask, band, fixed_rate, fixed_nss);
 }
 
 static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif,
@@ -4171,16 +4249,16 @@ static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif,
                goto exit;
 
        if (fixed_rate == WMI_FIXED_RATE_NONE)
-               ath10k_dbg(ATH10K_DBG_MAC, "mac disable fixed bitrate mask\n");
+               ath10k_dbg(ar, ATH10K_DBG_MAC, "mac disable fixed bitrate mask\n");
 
        if (force_sgi)
-               ath10k_dbg(ATH10K_DBG_MAC, "mac force sgi\n");
+               ath10k_dbg(ar, ATH10K_DBG_MAC, "mac force sgi\n");
 
        vdev_param = ar->wmi.vdev_param->fixed_rate;
        ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
                                        vdev_param, fixed_rate);
        if (ret) {
-               ath10k_warn("failed to set fixed rate param 0x%02x: %d\n",
+               ath10k_warn(ar, "failed to set fixed rate param 0x%02x: %d\n",
                            fixed_rate, ret);
                ret = -EINVAL;
                goto exit;
@@ -4193,7 +4271,7 @@ static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif,
                                        vdev_param, fixed_nss);
 
        if (ret) {
-               ath10k_warn("failed to set fixed nss param %d: %d\n",
+               ath10k_warn(ar, "failed to set fixed nss param %d: %d\n",
                            fixed_nss, ret);
                ret = -EINVAL;
                goto exit;
@@ -4206,7 +4284,7 @@ static int ath10k_set_fixed_rate_param(struct ath10k_vif *arvif,
                                        force_sgi);
 
        if (ret) {
-               ath10k_warn("failed to set sgi param %d: %d\n",
+               ath10k_warn(ar, "failed to set sgi param %d: %d\n",
                            force_sgi, ret);
                ret = -EINVAL;
                goto exit;
@@ -4235,14 +4313,14 @@ static int ath10k_set_bitrate_mask(struct ieee80211_hw *hw,
                return -EINVAL;
 
        if (!ath10k_default_bitrate_mask(ar, band, mask)) {
-               if (!ath10k_get_fixed_rate_nss(mask, band,
+               if (!ath10k_get_fixed_rate_nss(ar, mask, band,
                                               &fixed_rate,
                                               &fixed_nss))
                        return -EINVAL;
        }
 
        if (fixed_rate == WMI_FIXED_RATE_NONE && force_sgi) {
-               ath10k_warn("failed to force SGI usage for default rate settings\n");
+               ath10k_warn(ar, "failed to force SGI usage for default rate settings\n");
                return -EINVAL;
        }
 
@@ -4261,7 +4339,7 @@ static void ath10k_sta_rc_update(struct ieee80211_hw *hw,
 
        spin_lock_bh(&ar->data_lock);
 
-       ath10k_dbg(ATH10K_DBG_MAC,
+       ath10k_dbg(ar, ATH10K_DBG_MAC,
                   "mac sta rc update for %pM changed %08x bw %d nss %d smps %d\n",
                   sta->addr, changed, sta->bandwidth, sta->rx_nss,
                   sta->smps_mode);
@@ -4280,7 +4358,7 @@ static void ath10k_sta_rc_update(struct ieee80211_hw *hw,
                        bw = WMI_PEER_CHWIDTH_80MHZ;
                        break;
                case IEEE80211_STA_RX_BW_160:
-                       ath10k_warn("Invalid bandwith %d in rc update for %pM\n",
+                       ath10k_warn(ar, "Invalid bandwith %d in rc update for %pM\n",
                                    sta->bandwidth, sta->addr);
                        bw = WMI_PEER_CHWIDTH_20MHZ;
                        break;
@@ -4307,7 +4385,7 @@ static void ath10k_sta_rc_update(struct ieee80211_hw *hw,
                        smps = WMI_PEER_SMPS_DYNAMIC;
                        break;
                case IEEE80211_SMPS_NUM_MODES:
-                       ath10k_warn("Invalid smps %d in sta rc update for %pM\n",
+                       ath10k_warn(ar, "Invalid smps %d in sta rc update for %pM\n",
                                    sta->smps_mode, sta->addr);
                        smps = WMI_PEER_SMPS_PS_NONE;
                        break;
@@ -4339,9 +4417,10 @@ static int ath10k_ampdu_action(struct ieee80211_hw *hw,
                               struct ieee80211_sta *sta, u16 tid, u16 *ssn,
                               u8 buf_size)
 {
+       struct ath10k *ar = hw->priv;
        struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
 
-       ath10k_dbg(ATH10K_DBG_MAC, "mac ampdu vdev_id %i sta %pM tid %hu action %d\n",
+       ath10k_dbg(ar, ATH10K_DBG_MAC, "mac ampdu vdev_id %i sta %pM tid %hu action %d\n",
                   arvif->vdev_id, sta->addr, tid, action);
 
        switch (action) {
@@ -4489,12 +4568,12 @@ static struct ieee80211_rate ath10k_rates[] = {
 #define ath10k_g_rates (ath10k_rates + 0)
 #define ath10k_g_rates_size (ARRAY_SIZE(ath10k_rates))
 
-struct ath10k *ath10k_mac_create(void)
+struct ath10k *ath10k_mac_create(size_t priv_size)
 {
        struct ieee80211_hw *hw;
        struct ath10k *ar;
 
-       hw = ieee80211_alloc_hw(sizeof(struct ath10k), &ath10k_ops);
+       hw = ieee80211_alloc_hw(sizeof(struct ath10k) + priv_size, &ath10k_ops);
        if (!hw)
                return NULL;
 
@@ -4669,7 +4748,7 @@ struct ath10k_vif *ath10k_get_arvif(struct ath10k *ar, u32 vdev_id)
                                                   ath10k_get_arvif_iter,
                                                   &arvif_iter);
        if (!arvif_iter.arvif) {
-               ath10k_warn("No VIF found for vdev %d\n", vdev_id);
+               ath10k_warn(ar, "No VIF found for vdev %d\n", vdev_id);
                return NULL;
        }
 
@@ -4815,19 +4894,19 @@ int ath10k_mac_register(struct ath10k *ar)
                                                             NL80211_DFS_UNSET);
 
                if (!ar->dfs_detector)
-                       ath10k_warn("failed to initialise DFS pattern detector\n");
+                       ath10k_warn(ar, "failed to initialise DFS pattern detector\n");
        }
 
        ret = ath_regd_init(&ar->ath_common.regulatory, ar->hw->wiphy,
                            ath10k_reg_notifier);
        if (ret) {
-               ath10k_err("failed to initialise regulatory: %i\n", ret);
+               ath10k_err(ar, "failed to initialise regulatory: %i\n", ret);
                goto err_free;
        }
 
        ret = ieee80211_register_hw(ar->hw);
        if (ret) {
-               ath10k_err("failed to register ieee80211: %d\n", ret);
+               ath10k_err(ar, "failed to register ieee80211: %d\n", ret);
                goto err_free;
        }
 
index ef4f84376d7c2fe7d16432621b7f067ccb620992..6c80eeada3e28863bb1fe22e753251b64f73608d 100644 (file)
@@ -26,12 +26,14 @@ struct ath10k_generic_iter {
        int ret;
 };
 
-struct ath10k *ath10k_mac_create(void);
+struct ath10k *ath10k_mac_create(size_t priv_size);
 void ath10k_mac_destroy(struct ath10k *ar);
 int ath10k_mac_register(struct ath10k *ar);
 void ath10k_mac_unregister(struct ath10k *ar);
 struct ath10k_vif *ath10k_get_arvif(struct ath10k *ar, u32 vdev_id);
-void ath10k_reset_scan(unsigned long ptr);
+void __ath10k_scan_finish(struct ath10k *ar);
+void ath10k_scan_finish(struct ath10k *ar);
+void ath10k_scan_timeout_work(struct work_struct *work);
 void ath10k_offchan_tx_purge(struct ath10k *ar);
 void ath10k_offchan_tx_work(struct work_struct *work);
 void ath10k_mgmt_over_wmi_tx_purge(struct ath10k *ar);
index 3376963a4862db7f133064b6b8869c56b2c39c71..056a35a77133f5e1aee4f2ce8b4afb26859b02cb 100644 (file)
@@ -44,13 +44,9 @@ enum ath10k_pci_reset_mode {
        ATH10K_PCI_RESET_WARM_ONLY = 1,
 };
 
-static unsigned int ath10k_pci_target_ps;
 static unsigned int ath10k_pci_irq_mode = ATH10K_PCI_IRQ_AUTO;
 static unsigned int ath10k_pci_reset_mode = ATH10K_PCI_RESET_AUTO;
 
-module_param_named(target_ps, ath10k_pci_target_ps, uint, 0644);
-MODULE_PARM_DESC(target_ps, "Enable ath10k Target (SoC) PS option");
-
 module_param_named(irq_mode, ath10k_pci_irq_mode, uint, 0644);
 MODULE_PARM_DESC(irq_mode, "0: auto, 1: legacy, 2: msi (default: 0)");
 
@@ -71,10 +67,7 @@ static const struct pci_device_id ath10k_pci_id_table[] = {
 static int ath10k_pci_diag_read_access(struct ath10k *ar, u32 address,
                                       u32 *data);
 
-static int ath10k_pci_post_rx(struct ath10k *ar);
-static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info,
-                                            int num);
-static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info);
+static void ath10k_pci_buffer_cleanup(struct ath10k *ar);
 static int ath10k_pci_cold_reset(struct ath10k *ar);
 static int ath10k_pci_warm_reset(struct ath10k *ar);
 static int ath10k_pci_wait_for_target_init(struct ath10k *ar);
@@ -156,79 +149,175 @@ static const struct ce_attr host_ce_config_wlan[] = {
 static const struct ce_pipe_config target_ce_config_wlan[] = {
        /* CE0: host->target HTC control and raw streams */
        {
-               .pipenum = 0,
-               .pipedir = PIPEDIR_OUT,
-               .nentries = 32,
-               .nbytes_max = 256,
-               .flags = CE_ATTR_FLAGS,
-               .reserved = 0,
+               .pipenum = __cpu_to_le32(0),
+               .pipedir = __cpu_to_le32(PIPEDIR_OUT),
+               .nentries = __cpu_to_le32(32),
+               .nbytes_max = __cpu_to_le32(256),
+               .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+               .reserved = __cpu_to_le32(0),
        },
 
        /* CE1: target->host HTT + HTC control */
        {
-               .pipenum = 1,
-               .pipedir = PIPEDIR_IN,
-               .nentries = 32,
-               .nbytes_max = 512,
-               .flags = CE_ATTR_FLAGS,
-               .reserved = 0,
+               .pipenum = __cpu_to_le32(1),
+               .pipedir = __cpu_to_le32(PIPEDIR_IN),
+               .nentries = __cpu_to_le32(32),
+               .nbytes_max = __cpu_to_le32(512),
+               .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+               .reserved = __cpu_to_le32(0),
        },
 
        /* CE2: target->host WMI */
        {
-               .pipenum = 2,
-               .pipedir = PIPEDIR_IN,
-               .nentries = 32,
-               .nbytes_max = 2048,
-               .flags = CE_ATTR_FLAGS,
-               .reserved = 0,
+               .pipenum = __cpu_to_le32(2),
+               .pipedir = __cpu_to_le32(PIPEDIR_IN),
+               .nentries = __cpu_to_le32(32),
+               .nbytes_max = __cpu_to_le32(2048),
+               .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+               .reserved = __cpu_to_le32(0),
        },
 
        /* CE3: host->target WMI */
        {
-               .pipenum = 3,
-               .pipedir = PIPEDIR_OUT,
-               .nentries = 32,
-               .nbytes_max = 2048,
-               .flags = CE_ATTR_FLAGS,
-               .reserved = 0,
+               .pipenum = __cpu_to_le32(3),
+               .pipedir = __cpu_to_le32(PIPEDIR_OUT),
+               .nentries = __cpu_to_le32(32),
+               .nbytes_max = __cpu_to_le32(2048),
+               .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+               .reserved = __cpu_to_le32(0),
        },
 
        /* CE4: host->target HTT */
        {
-               .pipenum = 4,
-               .pipedir = PIPEDIR_OUT,
-               .nentries = 256,
-               .nbytes_max = 256,
-               .flags = CE_ATTR_FLAGS,
-               .reserved = 0,
+               .pipenum = __cpu_to_le32(4),
+               .pipedir = __cpu_to_le32(PIPEDIR_OUT),
+               .nentries = __cpu_to_le32(256),
+               .nbytes_max = __cpu_to_le32(256),
+               .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+               .reserved = __cpu_to_le32(0),
        },
 
        /* NB: 50% of src nentries, since tx has 2 frags */
 
        /* CE5: unused */
        {
-               .pipenum = 5,
-               .pipedir = PIPEDIR_OUT,
-               .nentries = 32,
-               .nbytes_max = 2048,
-               .flags = CE_ATTR_FLAGS,
-               .reserved = 0,
+               .pipenum = __cpu_to_le32(5),
+               .pipedir = __cpu_to_le32(PIPEDIR_OUT),
+               .nentries = __cpu_to_le32(32),
+               .nbytes_max = __cpu_to_le32(2048),
+               .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+               .reserved = __cpu_to_le32(0),
        },
 
        /* CE6: Reserved for target autonomous hif_memcpy */
        {
-               .pipenum = 6,
-               .pipedir = PIPEDIR_INOUT,
-               .nentries = 32,
-               .nbytes_max = 4096,
-               .flags = CE_ATTR_FLAGS,
-               .reserved = 0,
+               .pipenum = __cpu_to_le32(6),
+               .pipedir = __cpu_to_le32(PIPEDIR_INOUT),
+               .nentries = __cpu_to_le32(32),
+               .nbytes_max = __cpu_to_le32(4096),
+               .flags = __cpu_to_le32(CE_ATTR_FLAGS),
+               .reserved = __cpu_to_le32(0),
        },
 
        /* CE7 used only by Host */
 };
 
+/*
+ * Map from service/endpoint to Copy Engine.
+ * This table is derived from the CE_PCI TABLE, above.
+ * It is passed to the Target at startup for use by firmware.
+ */
+static const struct service_to_pipe target_service_to_ce_map_wlan[] = {
+       {
+               __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO),
+               __cpu_to_le32(PIPEDIR_OUT),     /* out = UL = host -> target */
+               __cpu_to_le32(3),
+       },
+       {
+               __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO),
+               __cpu_to_le32(PIPEDIR_IN),      /* in = DL = target -> host */
+               __cpu_to_le32(2),
+       },
+       {
+               __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BK),
+               __cpu_to_le32(PIPEDIR_OUT),     /* out = UL = host -> target */
+               __cpu_to_le32(3),
+       },
+       {
+               __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BK),
+               __cpu_to_le32(PIPEDIR_IN),      /* in = DL = target -> host */
+               __cpu_to_le32(2),
+       },
+       {
+               __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BE),
+               __cpu_to_le32(PIPEDIR_OUT),     /* out = UL = host -> target */
+               __cpu_to_le32(3),
+       },
+       {
+               __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BE),
+               __cpu_to_le32(PIPEDIR_IN),      /* in = DL = target -> host */
+               __cpu_to_le32(2),
+       },
+       {
+               __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VI),
+               __cpu_to_le32(PIPEDIR_OUT),     /* out = UL = host -> target */
+               __cpu_to_le32(3),
+       },
+       {
+               __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VI),
+               __cpu_to_le32(PIPEDIR_IN),      /* in = DL = target -> host */
+               __cpu_to_le32(2),
+       },
+       {
+               __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_CONTROL),
+               __cpu_to_le32(PIPEDIR_OUT),     /* out = UL = host -> target */
+               __cpu_to_le32(3),
+       },
+       {
+               __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_CONTROL),
+               __cpu_to_le32(PIPEDIR_IN),      /* in = DL = target -> host */
+               __cpu_to_le32(2),
+       },
+       {
+               __cpu_to_le32(ATH10K_HTC_SVC_ID_RSVD_CTRL),
+               __cpu_to_le32(PIPEDIR_OUT),     /* out = UL = host -> target */
+               __cpu_to_le32(0),
+       },
+       {
+               __cpu_to_le32(ATH10K_HTC_SVC_ID_RSVD_CTRL),
+               __cpu_to_le32(PIPEDIR_IN),      /* in = DL = target -> host */
+               __cpu_to_le32(1),
+       },
+       { /* not used */
+               __cpu_to_le32(ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS),
+               __cpu_to_le32(PIPEDIR_OUT),     /* out = UL = host -> target */
+               __cpu_to_le32(0),
+       },
+       { /* not used */
+               __cpu_to_le32(ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS),
+               __cpu_to_le32(PIPEDIR_IN),      /* in = DL = target -> host */
+               __cpu_to_le32(1),
+       },
+       {
+               __cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA_MSG),
+               __cpu_to_le32(PIPEDIR_OUT),     /* out = UL = host -> target */
+               __cpu_to_le32(4),
+       },
+       {
+               __cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA_MSG),
+               __cpu_to_le32(PIPEDIR_IN),      /* in = DL = target -> host */
+               __cpu_to_le32(1),
+       },
+
+       /* (Additions here) */
+
+       { /* must be last */
+               __cpu_to_le32(0),
+               __cpu_to_le32(0),
+               __cpu_to_le32(0),
+       },
+};
+
 static bool ath10k_pci_irq_pending(struct ath10k *ar)
 {
        u32 cause;
@@ -270,44 +359,111 @@ static void ath10k_pci_enable_legacy_irq(struct ath10k *ar)
                                 PCIE_INTR_ENABLE_ADDRESS);
 }
 
-static irqreturn_t ath10k_pci_early_irq_handler(int irq, void *arg)
+static inline const char *ath10k_pci_get_irq_method(struct ath10k *ar)
 {
-       struct ath10k *ar = arg;
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 
-       if (ar_pci->num_msi_intrs == 0) {
-               if (!ath10k_pci_irq_pending(ar))
-                       return IRQ_NONE;
-
-               ath10k_pci_disable_and_clear_legacy_irq(ar);
-       }
-
-       tasklet_schedule(&ar_pci->early_irq_tasklet);
-
-       return IRQ_HANDLED;
+       if (ar_pci->num_msi_intrs > 1)
+               return "msi-x";
+       else if (ar_pci->num_msi_intrs == 1)
+               return "msi";
+       else
+               return "legacy";
 }
 
-static int ath10k_pci_request_early_irq(struct ath10k *ar)
+static int __ath10k_pci_rx_post_buf(struct ath10k_pci_pipe *pipe)
 {
+       struct ath10k *ar = pipe->hif_ce_state;
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+       struct ath10k_ce_pipe *ce_pipe = pipe->ce_hdl;
+       struct sk_buff *skb;
+       dma_addr_t paddr;
        int ret;
 
-       /* Regardless whether MSI-X/MSI/legacy irqs have been set up the first
-        * interrupt from irq vector is triggered in all cases for FW
-        * indication/errors */
-       ret = request_irq(ar_pci->pdev->irq, ath10k_pci_early_irq_handler,
-                         IRQF_SHARED, "ath10k_pci (early)", ar);
+       lockdep_assert_held(&ar_pci->ce_lock);
+
+       skb = dev_alloc_skb(pipe->buf_sz);
+       if (!skb)
+               return -ENOMEM;
+
+       WARN_ONCE((unsigned long)skb->data & 3, "unaligned skb");
+
+       paddr = dma_map_single(ar->dev, skb->data,
+                              skb->len + skb_tailroom(skb),
+                              DMA_FROM_DEVICE);
+       if (unlikely(dma_mapping_error(ar->dev, paddr))) {
+               ath10k_warn(ar, "failed to dma map pci rx buf\n");
+               dev_kfree_skb_any(skb);
+               return -EIO;
+       }
+
+       ATH10K_SKB_CB(skb)->paddr = paddr;
+
+       ret = __ath10k_ce_rx_post_buf(ce_pipe, skb, paddr);
        if (ret) {
-               ath10k_warn("failed to request early irq: %d\n", ret);
+               ath10k_warn(ar, "failed to post pci rx buf: %d\n", ret);
+               dma_unmap_single(ar->dev, paddr, skb->len + skb_tailroom(skb),
+                                DMA_FROM_DEVICE);
+               dev_kfree_skb_any(skb);
                return ret;
        }
 
        return 0;
 }
 
-static void ath10k_pci_free_early_irq(struct ath10k *ar)
+static void __ath10k_pci_rx_post_pipe(struct ath10k_pci_pipe *pipe)
 {
-       free_irq(ath10k_pci_priv(ar)->pdev->irq, ar);
+       struct ath10k *ar = pipe->hif_ce_state;
+       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+       struct ath10k_ce_pipe *ce_pipe = pipe->ce_hdl;
+       int ret, num;
+
+       lockdep_assert_held(&ar_pci->ce_lock);
+
+       if (pipe->buf_sz == 0)
+               return;
+
+       if (!ce_pipe->dest_ring)
+               return;
+
+       num = __ath10k_ce_rx_num_free_bufs(ce_pipe);
+       while (num--) {
+               ret = __ath10k_pci_rx_post_buf(pipe);
+               if (ret) {
+                       ath10k_warn(ar, "failed to post pci rx buf: %d\n", ret);
+                       mod_timer(&ar_pci->rx_post_retry, jiffies +
+                                 ATH10K_PCI_RX_POST_RETRY_MS);
+                       break;
+               }
+       }
+}
+
+static void ath10k_pci_rx_post_pipe(struct ath10k_pci_pipe *pipe)
+{
+       struct ath10k *ar = pipe->hif_ce_state;
+       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+
+       spin_lock_bh(&ar_pci->ce_lock);
+       __ath10k_pci_rx_post_pipe(pipe);
+       spin_unlock_bh(&ar_pci->ce_lock);
+}
+
+static void ath10k_pci_rx_post(struct ath10k *ar)
+{
+       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+       int i;
+
+       spin_lock_bh(&ar_pci->ce_lock);
+       for (i = 0; i < CE_COUNT; i++)
+               __ath10k_pci_rx_post_pipe(&ar_pci->pipe_info[i]);
+       spin_unlock_bh(&ar_pci->ce_lock);
+}
+
+static void ath10k_pci_rx_replenish_retry(unsigned long ptr)
+{
+       struct ath10k *ar = (void *)ptr;
+
+       ath10k_pci_rx_post(ar);
 }
 
 /*
@@ -376,7 +532,7 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
                nbytes = min_t(unsigned int, remaining_bytes,
                               DIAG_TRANSFER_LIMIT);
 
-               ret = ath10k_ce_recv_buf_enqueue(ce_diag, NULL, ce_data);
+               ret = ath10k_ce_rx_post_buf(ce_diag, NULL, ce_data);
                if (ret != 0)
                        goto done;
 
@@ -389,10 +545,8 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
                 * convert it from Target CPU virtual address space
                 * to CE address space
                 */
-               ath10k_pci_wake(ar);
                address = TARG_CPU_SPACE_TO_CE_SPACE(ar, ar_pci->mem,
                                                     address);
-               ath10k_pci_sleep(ar);
 
                ret = ath10k_ce_send(ce_diag, NULL, (u32)address, nbytes, 0,
                                 0);
@@ -448,15 +602,10 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
        }
 
 done:
-       if (ret == 0) {
-               /* Copy data from allocated DMA buf to caller's buf */
-               WARN_ON_ONCE(orig_nbytes & 3);
-               for (i = 0; i < orig_nbytes / sizeof(__le32); i++) {
-                       ((u32 *)data)[i] =
-                               __le32_to_cpu(((__le32 *)data_buf)[i]);
-               }
-       } else
-               ath10k_warn("failed to read diag value at 0x%x: %d\n",
+       if (ret == 0)
+               memcpy(data, data_buf, orig_nbytes);
+       else
+               ath10k_warn(ar, "failed to read diag value at 0x%x: %d\n",
                            address, ret);
 
        if (data_buf)
@@ -466,17 +615,54 @@ done:
        return ret;
 }
 
+static int ath10k_pci_diag_read32(struct ath10k *ar, u32 address, u32 *value)
+{
+       __le32 val = 0;
+       int ret;
+
+       ret = ath10k_pci_diag_read_mem(ar, address, &val, sizeof(val));
+       *value = __le32_to_cpu(val);
+
+       return ret;
+}
+
+static int __ath10k_pci_diag_read_hi(struct ath10k *ar, void *dest,
+                                    u32 src, u32 len)
+{
+       u32 host_addr, addr;
+       int ret;
+
+       host_addr = host_interest_item_address(src);
+
+       ret = ath10k_pci_diag_read32(ar, host_addr, &addr);
+       if (ret != 0) {
+               ath10k_warn(ar, "failed to get memcpy hi address for firmware address %d: %d\n",
+                           src, ret);
+               return ret;
+       }
+
+       ret = ath10k_pci_diag_read_mem(ar, addr, dest, len);
+       if (ret != 0) {
+               ath10k_warn(ar, "failed to memcpy firmware memory from %d (%d B): %d\n",
+                           addr, len, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+#define ath10k_pci_diag_read_hi(ar, dest, src, len)            \
+       __ath10k_pci_diag_read_hi(ar, dest, HI_ITEM(src), len);
+
 /* Read 4-byte aligned data from Target memory or register */
 static int ath10k_pci_diag_read_access(struct ath10k *ar, u32 address,
                                       u32 *data)
 {
        /* Assume range doesn't cross this boundary */
        if (address >= DRAM_BASE_ADDRESS)
-               return ath10k_pci_diag_read_mem(ar, address, data, sizeof(u32));
+               return ath10k_pci_diag_read32(ar, address, data);
 
-       ath10k_pci_wake(ar);
        *data = ath10k_pci_read32(ar, address);
-       ath10k_pci_sleep(ar);
        return 0;
 }
 
@@ -514,9 +700,7 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
        }
 
        /* Copy caller's data to allocated DMA buf */
-       WARN_ON_ONCE(orig_nbytes & 3);
-       for (i = 0; i < orig_nbytes / sizeof(__le32); i++)
-               ((__le32 *)data_buf)[i] = __cpu_to_le32(((u32 *)data)[i]);
+       memcpy(data_buf, data, orig_nbytes);
 
        /*
         * The address supplied by the caller is in the
@@ -528,9 +712,7 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
         * to
         *    CE address space
         */
-       ath10k_pci_wake(ar);
        address = TARG_CPU_SPACE_TO_CE_SPACE(ar, ar_pci->mem, address);
-       ath10k_pci_sleep(ar);
 
        remaining_bytes = orig_nbytes;
        ce_data = ce_data_base;
@@ -539,7 +721,7 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
                nbytes = min_t(int, remaining_bytes, DIAG_TRANSFER_LIMIT);
 
                /* Set up to receive directly into Target(!) address */
-               ret = ath10k_ce_recv_buf_enqueue(ce_diag, NULL, address);
+               ret = ath10k_ce_rx_post_buf(ce_diag, NULL, address);
                if (ret != 0)
                        goto done;
 
@@ -608,66 +790,46 @@ done:
        }
 
        if (ret != 0)
-               ath10k_warn("failed to write diag value at 0x%x: %d\n",
+               ath10k_warn(ar, "failed to write diag value at 0x%x: %d\n",
                            address, ret);
 
        return ret;
 }
 
+static int ath10k_pci_diag_write32(struct ath10k *ar, u32 address, u32 value)
+{
+       __le32 val = __cpu_to_le32(value);
+
+       return ath10k_pci_diag_write_mem(ar, address, &val, sizeof(val));
+}
+
 /* Write 4B data to Target memory or register */
 static int ath10k_pci_diag_write_access(struct ath10k *ar, u32 address,
                                        u32 data)
 {
        /* Assume range doesn't cross this boundary */
        if (address >= DRAM_BASE_ADDRESS)
-               return ath10k_pci_diag_write_mem(ar, address, &data,
-                                                sizeof(u32));
+               return ath10k_pci_diag_write32(ar, address, data);
 
-       ath10k_pci_wake(ar);
        ath10k_pci_write32(ar, address, data);
-       ath10k_pci_sleep(ar);
        return 0;
 }
 
-static bool ath10k_pci_target_is_awake(struct ath10k *ar)
+static bool ath10k_pci_is_awake(struct ath10k *ar)
 {
-       void __iomem *mem = ath10k_pci_priv(ar)->mem;
-       u32 val;
-       val = ioread32(mem + PCIE_LOCAL_BASE_ADDRESS +
-                      RTC_STATE_ADDRESS);
-       return (RTC_STATE_V_GET(val) == RTC_STATE_V_ON);
+       u32 val = ath10k_pci_reg_read32(ar, RTC_STATE_ADDRESS);
+
+       return RTC_STATE_V_GET(val) == RTC_STATE_V_ON;
 }
 
-int ath10k_do_pci_wake(struct ath10k *ar)
+static int ath10k_pci_wake_wait(struct ath10k *ar)
 {
-       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       void __iomem *pci_addr = ar_pci->mem;
        int tot_delay = 0;
        int curr_delay = 5;
 
-       if (atomic_read(&ar_pci->keep_awake_count) == 0) {
-               /* Force AWAKE */
-               iowrite32(PCIE_SOC_WAKE_V_MASK,
-                         pci_addr + PCIE_LOCAL_BASE_ADDRESS +
-                         PCIE_SOC_WAKE_ADDRESS);
-       }
-       atomic_inc(&ar_pci->keep_awake_count);
-
-       if (ar_pci->verified_awake)
-               return 0;
-
-       for (;;) {
-               if (ath10k_pci_target_is_awake(ar)) {
-                       ar_pci->verified_awake = true;
+       while (tot_delay < PCIE_WAKE_TIMEOUT) {
+               if (ath10k_pci_is_awake(ar))
                        return 0;
-               }
-
-               if (tot_delay > PCIE_WAKE_TIMEOUT) {
-                       ath10k_warn("target took longer %d us to wake up (awake count %d)\n",
-                                   PCIE_WAKE_TIMEOUT,
-                                   atomic_read(&ar_pci->keep_awake_count));
-                       return -ETIMEDOUT;
-               }
 
                udelay(curr_delay);
                tot_delay += curr_delay;
@@ -675,20 +837,21 @@ int ath10k_do_pci_wake(struct ath10k *ar)
                if (curr_delay < 50)
                        curr_delay += 5;
        }
+
+       return -ETIMEDOUT;
 }
 
-void ath10k_do_pci_sleep(struct ath10k *ar)
+static int ath10k_pci_wake(struct ath10k *ar)
 {
-       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       void __iomem *pci_addr = ar_pci->mem;
+       ath10k_pci_reg_write32(ar, PCIE_SOC_WAKE_ADDRESS,
+                              PCIE_SOC_WAKE_V_MASK);
+       return ath10k_pci_wake_wait(ar);
+}
 
-       if (atomic_dec_and_test(&ar_pci->keep_awake_count)) {
-               /* Allow sleep */
-               ar_pci->verified_awake = false;
-               iowrite32(PCIE_SOC_WAKE_RESET,
-                         pci_addr + PCIE_LOCAL_BASE_ADDRESS +
-                         PCIE_SOC_WAKE_ADDRESS);
-       }
+static void ath10k_pci_sleep(struct ath10k *ar)
+{
+       ath10k_pci_reg_write32(ar, PCIE_SOC_WAKE_ADDRESS,
+                              PCIE_SOC_WAKE_RESET);
 }
 
 /* Called by lower (CE) layer when a send to Target completes. */
@@ -726,19 +889,17 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state)
        unsigned int nbytes, max_nbytes;
        unsigned int transfer_id;
        unsigned int flags;
-       int err, num_replenish = 0;
 
        while (ath10k_ce_completed_recv_next(ce_state, &transfer_context,
                                             &ce_data, &nbytes, &transfer_id,
                                             &flags) == 0) {
-               num_replenish++;
                skb = transfer_context;
                max_nbytes = skb->len + skb_tailroom(skb);
                dma_unmap_single(ar->dev, ATH10K_SKB_CB(skb)->paddr,
                                 max_nbytes, DMA_FROM_DEVICE);
 
                if (unlikely(max_nbytes < nbytes)) {
-                       ath10k_warn("rxed more than expected (nbytes %d, max %d)",
+                       ath10k_warn(ar, "rxed more than expected (nbytes %d, max %d)",
                                    nbytes, max_nbytes);
                        dev_kfree_skb_any(skb);
                        continue;
@@ -748,12 +909,7 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state)
                cb->rx_completion(ar, skb, pipe_info->pipe_num);
        }
 
-       err = ath10k_pci_post_rx_pipe(pipe_info, num_replenish);
-       if (unlikely(err)) {
-               /* FIXME: retry */
-               ath10k_warn("failed to replenish CE rx ring %d (%d bufs): %d\n",
-                           pipe_info->pipe_num, num_replenish, err);
-       }
+       ath10k_pci_rx_post_pipe(pipe_info);
 }
 
 static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
@@ -781,10 +937,10 @@ static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
        }
 
        for (i = 0; i < n_items - 1; i++) {
-               ath10k_dbg(ATH10K_DBG_PCI,
+               ath10k_dbg(ar, ATH10K_DBG_PCI,
                           "pci tx item %d paddr 0x%08x len %d n_items %d\n",
                           i, items[i].paddr, items[i].len, n_items);
-               ath10k_dbg_dump(ATH10K_DBG_PCI_DUMP, NULL, "item data: ",
+               ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci tx data: ",
                                items[i].vaddr, items[i].len);
 
                err = ath10k_ce_send_nolock(ce_pipe,
@@ -799,10 +955,10 @@ static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
 
        /* `i` is equal to `n_items -1` after for() */
 
-       ath10k_dbg(ATH10K_DBG_PCI,
+       ath10k_dbg(ar, ATH10K_DBG_PCI,
                   "pci tx item %d paddr 0x%08x len %d n_items %d\n",
                   i, items[i].paddr, items[i].len, n_items);
-       ath10k_dbg_dump(ATH10K_DBG_PCI_DUMP, NULL, "item data: ",
+       ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci tx data: ",
                        items[i].vaddr, items[i].len);
 
        err = ath10k_ce_send_nolock(ce_pipe,
@@ -829,52 +985,64 @@ static u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 
-       ath10k_dbg(ATH10K_DBG_PCI, "pci hif get free queue number\n");
+       ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif get free queue number\n");
 
        return ath10k_ce_num_free_src_entries(ar_pci->pipe_info[pipe].ce_hdl);
 }
 
-static void ath10k_pci_hif_dump_area(struct ath10k *ar)
+static void ath10k_pci_dump_registers(struct ath10k *ar,
+                                     struct ath10k_fw_crash_data *crash_data)
 {
-       u32 reg_dump_area = 0;
-       u32 reg_dump_values[REG_DUMP_COUNT_QCA988X] = {};
-       u32 host_addr;
-       int ret;
-       u32 i;
+       __le32 reg_dump_values[REG_DUMP_COUNT_QCA988X] = {};
+       int i, ret;
 
-       ath10k_err("firmware crashed!\n");
-       ath10k_err("hardware name %s version 0x%x\n",
-                  ar->hw_params.name, ar->target_version);
-       ath10k_err("firmware version: %s\n", ar->hw->wiphy->fw_version);
+       lockdep_assert_held(&ar->data_lock);
 
-       host_addr = host_interest_item_address(HI_ITEM(hi_failure_state));
-       ret = ath10k_pci_diag_read_mem(ar, host_addr,
-                                      &reg_dump_area, sizeof(u32));
+       ret = ath10k_pci_diag_read_hi(ar, &reg_dump_values[0],
+                                     hi_failure_state,
+                                     REG_DUMP_COUNT_QCA988X * sizeof(__le32));
        if (ret) {
-               ath10k_err("failed to read FW dump area address: %d\n", ret);
-               return;
-       }
-
-       ath10k_err("target register Dump Location: 0x%08X\n", reg_dump_area);
-
-       ret = ath10k_pci_diag_read_mem(ar, reg_dump_area,
-                                      &reg_dump_values[0],
-                                      REG_DUMP_COUNT_QCA988X * sizeof(u32));
-       if (ret != 0) {
-               ath10k_err("failed to read FW dump area: %d\n", ret);
+               ath10k_err(ar, "failed to read firmware dump area: %d\n", ret);
                return;
        }
 
        BUILD_BUG_ON(REG_DUMP_COUNT_QCA988X % 4);
 
-       ath10k_err("target Register Dump\n");
+       ath10k_err(ar, "firmware register dump:\n");
        for (i = 0; i < REG_DUMP_COUNT_QCA988X; i += 4)
-               ath10k_err("[%02d]: 0x%08X 0x%08X 0x%08X 0x%08X\n",
+               ath10k_err(ar, "[%02d]: 0x%08X 0x%08X 0x%08X 0x%08X\n",
                           i,
-                          reg_dump_values[i],
-                          reg_dump_values[i + 1],
-                          reg_dump_values[i + 2],
-                          reg_dump_values[i + 3]);
+                          __le32_to_cpu(reg_dump_values[i]),
+                          __le32_to_cpu(reg_dump_values[i + 1]),
+                          __le32_to_cpu(reg_dump_values[i + 2]),
+                          __le32_to_cpu(reg_dump_values[i + 3]));
+
+       if (!crash_data)
+               return;
+
+       for (i = 0; i < REG_DUMP_COUNT_QCA988X; i++)
+               crash_data->registers[i] = reg_dump_values[i];
+}
+
+static void ath10k_pci_fw_crashed_dump(struct ath10k *ar)
+{
+       struct ath10k_fw_crash_data *crash_data;
+       char uuid[50];
+
+       spin_lock_bh(&ar->data_lock);
+
+       crash_data = ath10k_debug_get_new_fw_crash_data(ar);
+
+       if (crash_data)
+               scnprintf(uuid, sizeof(uuid), "%pUl", &crash_data->uuid);
+       else
+               scnprintf(uuid, sizeof(uuid), "n/a");
+
+       ath10k_err(ar, "firmware crashed! (uuid %s)\n", uuid);
+       ath10k_print_driver_info(ar);
+       ath10k_pci_dump_registers(ar, crash_data);
+
+       spin_unlock_bh(&ar->data_lock);
 
        queue_work(ar->workqueue, &ar->restart_work);
 }
@@ -882,7 +1050,7 @@ static void ath10k_pci_hif_dump_area(struct ath10k *ar)
 static void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe,
                                               int force)
 {
-       ath10k_dbg(ATH10K_DBG_PCI, "pci hif send complete check\n");
+       ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif send complete check\n");
 
        if (!force) {
                int resources;
@@ -910,43 +1078,12 @@ static void ath10k_pci_hif_set_callbacks(struct ath10k *ar,
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 
-       ath10k_dbg(ATH10K_DBG_PCI, "pci hif set callbacks\n");
+       ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif set callbacks\n");
 
        memcpy(&ar_pci->msg_callbacks_current, callbacks,
               sizeof(ar_pci->msg_callbacks_current));
 }
 
-static int ath10k_pci_setup_ce_irq(struct ath10k *ar)
-{
-       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       const struct ce_attr *attr;
-       struct ath10k_pci_pipe *pipe_info;
-       int pipe_num, disable_interrupts;
-
-       for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {
-               pipe_info = &ar_pci->pipe_info[pipe_num];
-
-               /* Handle Diagnostic CE specially */
-               if (pipe_info->ce_hdl == ar_pci->ce_diag)
-                       continue;
-
-               attr = &host_ce_config_wlan[pipe_num];
-
-               if (attr->src_nentries) {
-                       disable_interrupts = attr->flags & CE_ATTR_DIS_INTR;
-                       ath10k_ce_send_cb_register(pipe_info->ce_hdl,
-                                                  ath10k_pci_ce_send_done,
-                                                  disable_interrupts);
-               }
-
-               if (attr->dest_nentries)
-                       ath10k_ce_recv_cb_register(pipe_info->ce_hdl,
-                                                  ath10k_pci_ce_recv_data);
-       }
-
-       return 0;
-}
-
 static void ath10k_pci_kill_tasklet(struct ath10k *ar)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
@@ -954,74 +1091,64 @@ static void ath10k_pci_kill_tasklet(struct ath10k *ar)
 
        tasklet_kill(&ar_pci->intr_tq);
        tasklet_kill(&ar_pci->msi_fw_err);
-       tasklet_kill(&ar_pci->early_irq_tasklet);
 
        for (i = 0; i < CE_COUNT; i++)
                tasklet_kill(&ar_pci->pipe_info[i].intr);
+
+       del_timer_sync(&ar_pci->rx_post_retry);
 }
 
-/* TODO - temporary mapping while we have too few CE's */
 static int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar,
                                              u16 service_id, u8 *ul_pipe,
                                              u8 *dl_pipe, int *ul_is_polled,
                                              int *dl_is_polled)
 {
-       int ret = 0;
+       const struct service_to_pipe *entry;
+       bool ul_set = false, dl_set = false;
+       int i;
 
-       ath10k_dbg(ATH10K_DBG_PCI, "pci hif map service\n");
+       ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif map service\n");
 
        /* polling for received messages not supported */
        *dl_is_polled = 0;
 
-       switch (service_id) {
-       case ATH10K_HTC_SVC_ID_HTT_DATA_MSG:
-               /*
-                * Host->target HTT gets its own pipe, so it can be polled
-                * while other pipes are interrupt driven.
-                */
-               *ul_pipe = 4;
-               /*
-                * Use the same target->host pipe for HTC ctrl, HTC raw
-                * streams, and HTT.
-                */
-               *dl_pipe = 1;
-               break;
-
-       case ATH10K_HTC_SVC_ID_RSVD_CTRL:
-       case ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS:
-               /*
-                * Note: HTC_RAW_STREAMS_SVC is currently unused, and
-                * HTC_CTRL_RSVD_SVC could share the same pipe as the
-                * WMI services.  So, if another CE is needed, change
-                * this to *ul_pipe = 3, which frees up CE 0.
-                */
-               /* *ul_pipe = 3; */
-               *ul_pipe = 0;
-               *dl_pipe = 1;
-               break;
+       for (i = 0; i < ARRAY_SIZE(target_service_to_ce_map_wlan); i++) {
+               entry = &target_service_to_ce_map_wlan[i];
 
-       case ATH10K_HTC_SVC_ID_WMI_DATA_BK:
-       case ATH10K_HTC_SVC_ID_WMI_DATA_BE:
-       case ATH10K_HTC_SVC_ID_WMI_DATA_VI:
-       case ATH10K_HTC_SVC_ID_WMI_DATA_VO:
+               if (__le32_to_cpu(entry->service_id) != service_id)
+                       continue;
 
-       case ATH10K_HTC_SVC_ID_WMI_CONTROL:
-               *ul_pipe = 3;
-               *dl_pipe = 2;
-               break;
+               switch (__le32_to_cpu(entry->pipedir)) {
+               case PIPEDIR_NONE:
+                       break;
+               case PIPEDIR_IN:
+                       WARN_ON(dl_set);
+                       *dl_pipe = __le32_to_cpu(entry->pipenum);
+                       dl_set = true;
+                       break;
+               case PIPEDIR_OUT:
+                       WARN_ON(ul_set);
+                       *ul_pipe = __le32_to_cpu(entry->pipenum);
+                       ul_set = true;
+                       break;
+               case PIPEDIR_INOUT:
+                       WARN_ON(dl_set);
+                       WARN_ON(ul_set);
+                       *dl_pipe = __le32_to_cpu(entry->pipenum);
+                       *ul_pipe = __le32_to_cpu(entry->pipenum);
+                       dl_set = true;
+                       ul_set = true;
+                       break;
+               }
+       }
 
-               /* pipe 5 unused   */
-               /* pipe 6 reserved */
-               /* pipe 7 reserved */
+       if (WARN_ON(!ul_set || !dl_set))
+               return -ENOENT;
 
-       default:
-               ret = -1;
-               break;
-       }
        *ul_is_polled =
                (host_ce_config_wlan[*ul_pipe].flags & CE_ATTR_DIS_INTR) != 0;
 
-       return ret;
+       return 0;
 }
 
 static void ath10k_pci_hif_get_default_pipe(struct ath10k *ar,
@@ -1029,7 +1156,7 @@ static void ath10k_pci_hif_get_default_pipe(struct ath10k *ar,
 {
        int ul_is_polled, dl_is_polled;
 
-       ath10k_dbg(ATH10K_DBG_PCI, "pci hif get default pipe\n");
+       ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif get default pipe\n");
 
        (void)ath10k_pci_hif_map_service_to_pipe(ar,
                                                 ATH10K_HTC_SVC_ID_RSVD_CTRL,
@@ -1039,141 +1166,48 @@ static void ath10k_pci_hif_get_default_pipe(struct ath10k *ar,
                                                 &dl_is_polled);
 }
 
-static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info,
-                                  int num)
+static void ath10k_pci_irq_disable(struct ath10k *ar)
 {
-       struct ath10k *ar = pipe_info->hif_ce_state;
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       struct ath10k_ce_pipe *ce_state = pipe_info->ce_hdl;
-       struct sk_buff *skb;
-       dma_addr_t ce_data;
-       int i, ret = 0;
-
-       if (pipe_info->buf_sz == 0)
-               return 0;
-
-       for (i = 0; i < num; i++) {
-               skb = dev_alloc_skb(pipe_info->buf_sz);
-               if (!skb) {
-                       ath10k_warn("failed to allocate skbuff for pipe %d\n",
-                                   num);
-                       ret = -ENOMEM;
-                       goto err;
-               }
-
-               WARN_ONCE((unsigned long)skb->data & 3, "unaligned skb");
-
-               ce_data = dma_map_single(ar->dev, skb->data,
-                                        skb->len + skb_tailroom(skb),
-                                        DMA_FROM_DEVICE);
-
-               if (unlikely(dma_mapping_error(ar->dev, ce_data))) {
-                       ath10k_warn("failed to DMA map sk_buff\n");
-                       dev_kfree_skb_any(skb);
-                       ret = -EIO;
-                       goto err;
-               }
-
-               ATH10K_SKB_CB(skb)->paddr = ce_data;
-
-               pci_dma_sync_single_for_device(ar_pci->pdev, ce_data,
-                                              pipe_info->buf_sz,
-                                              PCI_DMA_FROMDEVICE);
+       int i;
 
-               ret = ath10k_ce_recv_buf_enqueue(ce_state, (void *)skb,
-                                                ce_data);
-               if (ret) {
-                       ath10k_warn("failed to enqueue to pipe %d: %d\n",
-                                   num, ret);
-                       goto err;
-               }
-       }
+       ath10k_ce_disable_interrupts(ar);
 
-       return ret;
+       /* Regardless how many interrupts were assigned for MSI the first one
+        * is always used for firmware indications (crashes). There's no way to
+        * mask the irq in the device so call disable_irq(). Legacy (shared)
+        * interrupts can be masked on the device though.
+        */
+       if (ar_pci->num_msi_intrs > 0)
+               disable_irq(ar_pci->pdev->irq);
+       else
+               ath10k_pci_disable_and_clear_legacy_irq(ar);
 
-err:
-       ath10k_pci_rx_pipe_cleanup(pipe_info);
-       return ret;
+       for (i = 0; i < max(1, ar_pci->num_msi_intrs); i++)
+               synchronize_irq(ar_pci->pdev->irq + i);
 }
 
-static int ath10k_pci_post_rx(struct ath10k *ar)
+static void ath10k_pci_irq_enable(struct ath10k *ar)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       struct ath10k_pci_pipe *pipe_info;
-       const struct ce_attr *attr;
-       int pipe_num, ret = 0;
-
-       for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {
-               pipe_info = &ar_pci->pipe_info[pipe_num];
-               attr = &host_ce_config_wlan[pipe_num];
 
-               if (attr->dest_nentries == 0)
-                       continue;
-
-               ret = ath10k_pci_post_rx_pipe(pipe_info,
-                                             attr->dest_nentries - 1);
-               if (ret) {
-                       ath10k_warn("failed to post RX buffer for pipe %d: %d\n",
-                                   pipe_num, ret);
-
-                       for (; pipe_num >= 0; pipe_num--) {
-                               pipe_info = &ar_pci->pipe_info[pipe_num];
-                               ath10k_pci_rx_pipe_cleanup(pipe_info);
-                       }
-                       return ret;
-               }
-       }
+       ath10k_ce_enable_interrupts(ar);
 
-       return 0;
+       /* See comment in ath10k_pci_irq_disable() */
+       if (ar_pci->num_msi_intrs > 0)
+               enable_irq(ar_pci->pdev->irq);
+       else
+               ath10k_pci_enable_legacy_irq(ar);
 }
 
 static int ath10k_pci_hif_start(struct ath10k *ar)
 {
-       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       int ret, ret_early;
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif start\n");
 
-       ath10k_dbg(ATH10K_DBG_BOOT, "boot hif start\n");
+       ath10k_pci_irq_enable(ar);
+       ath10k_pci_rx_post(ar);
 
-       ath10k_pci_free_early_irq(ar);
-       ath10k_pci_kill_tasklet(ar);
-
-       ret = ath10k_pci_request_irq(ar);
-       if (ret) {
-               ath10k_warn("failed to post RX buffers for all pipes: %d\n",
-                           ret);
-               goto err_early_irq;
-       }
-
-       ret = ath10k_pci_setup_ce_irq(ar);
-       if (ret) {
-               ath10k_warn("failed to setup CE interrupts: %d\n", ret);
-               goto err_stop;
-       }
-
-       /* Post buffers once to start things off. */
-       ret = ath10k_pci_post_rx(ar);
-       if (ret) {
-               ath10k_warn("failed to post RX buffers for all pipes: %d\n",
-                           ret);
-               goto err_stop;
-       }
-
-       ar_pci->started = 1;
        return 0;
-
-err_stop:
-       ath10k_ce_disable_interrupts(ar);
-       ath10k_pci_free_irq(ar);
-       ath10k_pci_kill_tasklet(ar);
-err_early_irq:
-       /* Though there should be no interrupts (device was reset)
-        * power_down() expects the early IRQ to be installed as per the
-        * driver lifecycle. */
-       ret_early = ath10k_pci_request_early_irq(ar);
-       if (ret_early)
-               ath10k_warn("failed to re-enable early irq: %d\n", ret_early);
-
-       return ret;
 }
 
 static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info)
@@ -1193,10 +1227,6 @@ static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info)
 
        ar = pipe_info->hif_ce_state;
        ar_pci = ath10k_pci_priv(ar);
-
-       if (!ar_pci->started)
-               return;
-
        ce_hdl = pipe_info->ce_hdl;
 
        while (ath10k_ce_revoke_recv_next(ce_hdl, (void **)&netbuf,
@@ -1227,10 +1257,6 @@ static void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info)
 
        ar = pipe_info->hif_ce_state;
        ar_pci = ath10k_pci_priv(ar);
-
-       if (!ar_pci->started)
-               return;
-
        ce_hdl = pipe_info->ce_hdl;
 
        while (ath10k_ce_cancel_send_next(ce_hdl, (void **)&netbuf,
@@ -1275,41 +1301,24 @@ static void ath10k_pci_ce_deinit(struct ath10k *ar)
                ath10k_ce_deinit_pipe(ar, i);
 }
 
-static void ath10k_pci_hif_stop(struct ath10k *ar)
+static void ath10k_pci_flush(struct ath10k *ar)
 {
-       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       int ret;
-
-       ath10k_dbg(ATH10K_DBG_BOOT, "boot hif stop\n");
-
-       if (WARN_ON(!ar_pci->started))
-               return;
-
-       ret = ath10k_ce_disable_interrupts(ar);
-       if (ret)
-               ath10k_warn("failed to disable CE interrupts: %d\n", ret);
-
-       ath10k_pci_free_irq(ar);
        ath10k_pci_kill_tasklet(ar);
+       ath10k_pci_buffer_cleanup(ar);
+}
 
-       ret = ath10k_pci_request_early_irq(ar);
-       if (ret)
-               ath10k_warn("failed to re-enable early irq: %d\n", ret);
-
-       /* At this point, asynchronous threads are stopped, the target should
-        * not DMA nor interrupt. We process the leftovers and then free
-        * everything else up. */
+static void ath10k_pci_hif_stop(struct ath10k *ar)
+{
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif stop\n");
 
-       ath10k_pci_buffer_cleanup(ar);
+       ath10k_pci_irq_disable(ar);
+       ath10k_pci_flush(ar);
 
-       /* Make the sure the device won't access any structures on the host by
-        * resetting it. The device was fed with PCI CE ringbuffer
-        * configuration during init. If ringbuffers are freed and the device
-        * were to access them this could lead to memory corruption on the
-        * host. */
+       /* Most likely the device has HTT Rx ring configured. The only way to
+        * prevent the device from accessing (and possible corrupting) host
+        * memory is to reset the chip now.
+        */
        ath10k_pci_warm_reset(ar);
-
-       ar_pci->started = 0;
 }
 
 static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,
@@ -1360,7 +1369,7 @@ static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,
                xfer.wait_for_resp = true;
                xfer.resp_len = 0;
 
-               ath10k_ce_recv_buf_enqueue(ce_rx, &xfer, resp_paddr);
+               ath10k_ce_rx_post_buf(ce_rx, &xfer, resp_paddr);
        }
 
        ret = ath10k_ce_send(ce_tx, &xfer, req_paddr, req_len, -1, 0);
@@ -1418,6 +1427,7 @@ static void ath10k_pci_bmi_send_done(struct ath10k_ce_pipe *ce_state)
 
 static void ath10k_pci_bmi_recv_data(struct ath10k_ce_pipe *ce_state)
 {
+       struct ath10k *ar = ce_state->ar;
        struct bmi_xfer *xfer;
        u32 ce_data;
        unsigned int nbytes;
@@ -1429,7 +1439,7 @@ static void ath10k_pci_bmi_recv_data(struct ath10k_ce_pipe *ce_state)
                return;
 
        if (!xfer->wait_for_resp) {
-               ath10k_warn("unexpected: BMI data received; ignoring\n");
+               ath10k_warn(ar, "unexpected: BMI data received; ignoring\n");
                return;
        }
 
@@ -1450,107 +1460,11 @@ static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe,
                if (xfer->tx_done && (xfer->rx_done == xfer->wait_for_resp))
                        return 0;
 
-               schedule();
-       }
-
-       return -ETIMEDOUT;
-}
-
-/*
- * Map from service/endpoint to Copy Engine.
- * This table is derived from the CE_PCI TABLE, above.
- * It is passed to the Target at startup for use by firmware.
- */
-static const struct service_to_pipe target_service_to_ce_map_wlan[] = {
-       {
-                ATH10K_HTC_SVC_ID_WMI_DATA_VO,
-                PIPEDIR_OUT,           /* out = UL = host -> target */
-                3,
-       },
-       {
-                ATH10K_HTC_SVC_ID_WMI_DATA_VO,
-                PIPEDIR_IN,            /* in = DL = target -> host */
-                2,
-       },
-       {
-                ATH10K_HTC_SVC_ID_WMI_DATA_BK,
-                PIPEDIR_OUT,           /* out = UL = host -> target */
-                3,
-       },
-       {
-                ATH10K_HTC_SVC_ID_WMI_DATA_BK,
-                PIPEDIR_IN,            /* in = DL = target -> host */
-                2,
-       },
-       {
-                ATH10K_HTC_SVC_ID_WMI_DATA_BE,
-                PIPEDIR_OUT,           /* out = UL = host -> target */
-                3,
-       },
-       {
-                ATH10K_HTC_SVC_ID_WMI_DATA_BE,
-                PIPEDIR_IN,            /* in = DL = target -> host */
-                2,
-       },
-       {
-                ATH10K_HTC_SVC_ID_WMI_DATA_VI,
-                PIPEDIR_OUT,           /* out = UL = host -> target */
-                3,
-       },
-       {
-                ATH10K_HTC_SVC_ID_WMI_DATA_VI,
-                PIPEDIR_IN,            /* in = DL = target -> host */
-                2,
-       },
-       {
-                ATH10K_HTC_SVC_ID_WMI_CONTROL,
-                PIPEDIR_OUT,           /* out = UL = host -> target */
-                3,
-       },
-       {
-                ATH10K_HTC_SVC_ID_WMI_CONTROL,
-                PIPEDIR_IN,            /* in = DL = target -> host */
-                2,
-       },
-       {
-                ATH10K_HTC_SVC_ID_RSVD_CTRL,
-                PIPEDIR_OUT,           /* out = UL = host -> target */
-                0,             /* could be moved to 3 (share with WMI) */
-       },
-       {
-                ATH10K_HTC_SVC_ID_RSVD_CTRL,
-                PIPEDIR_IN,            /* in = DL = target -> host */
-                1,
-       },
-       {
-                ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS,    /* not currently used */
-                PIPEDIR_OUT,           /* out = UL = host -> target */
-                0,
-       },
-       {
-                ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS,    /* not currently used */
-                PIPEDIR_IN,            /* in = DL = target -> host */
-                1,
-       },
-       {
-                ATH10K_HTC_SVC_ID_HTT_DATA_MSG,
-                PIPEDIR_OUT,           /* out = UL = host -> target */
-                4,
-       },
-       {
-                ATH10K_HTC_SVC_ID_HTT_DATA_MSG,
-                PIPEDIR_IN,            /* in = DL = target -> host */
-                1,
-       },
-
-       /* (Additions here) */
+               schedule();
+       }
 
-       {                               /* Must be last */
-                0,
-                0,
-                0,
-       },
-};
+       return -ETIMEDOUT;
+}
 
 /*
  * Send an interrupt to the device to wake up the Target CPU
@@ -1565,7 +1479,7 @@ static int ath10k_pci_wake_target_cpu(struct ath10k *ar)
                                              CORE_CTRL_ADDRESS,
                                          &core_ctrl);
        if (ret) {
-               ath10k_warn("failed to read core_ctrl: %d\n", ret);
+               ath10k_warn(ar, "failed to read core_ctrl: %d\n", ret);
                return ret;
        }
 
@@ -1576,7 +1490,7 @@ static int ath10k_pci_wake_target_cpu(struct ath10k *ar)
                                               CORE_CTRL_ADDRESS,
                                           core_ctrl);
        if (ret) {
-               ath10k_warn("failed to set target CPU interrupt mask: %d\n",
+               ath10k_warn(ar, "failed to set target CPU interrupt mask: %d\n",
                            ret);
                return ret;
        }
@@ -1605,13 +1519,13 @@ static int ath10k_pci_init_config(struct ath10k *ar)
        ret = ath10k_pci_diag_read_access(ar, interconnect_targ_addr,
                                          &pcie_state_targ_addr);
        if (ret != 0) {
-               ath10k_err("Failed to get pcie state addr: %d\n", ret);
+               ath10k_err(ar, "Failed to get pcie state addr: %d\n", ret);
                return ret;
        }
 
        if (pcie_state_targ_addr == 0) {
                ret = -EIO;
-               ath10k_err("Invalid pcie state addr\n");
+               ath10k_err(ar, "Invalid pcie state addr\n");
                return ret;
        }
 
@@ -1620,13 +1534,13 @@ static int ath10k_pci_init_config(struct ath10k *ar)
                                                   pipe_cfg_addr),
                                          &pipe_cfg_targ_addr);
        if (ret != 0) {
-               ath10k_err("Failed to get pipe cfg addr: %d\n", ret);
+               ath10k_err(ar, "Failed to get pipe cfg addr: %d\n", ret);
                return ret;
        }
 
        if (pipe_cfg_targ_addr == 0) {
                ret = -EIO;
-               ath10k_err("Invalid pipe cfg addr\n");
+               ath10k_err(ar, "Invalid pipe cfg addr\n");
                return ret;
        }
 
@@ -1635,7 +1549,7 @@ static int ath10k_pci_init_config(struct ath10k *ar)
                                 sizeof(target_ce_config_wlan));
 
        if (ret != 0) {
-               ath10k_err("Failed to write pipe cfg: %d\n", ret);
+               ath10k_err(ar, "Failed to write pipe cfg: %d\n", ret);
                return ret;
        }
 
@@ -1644,13 +1558,13 @@ static int ath10k_pci_init_config(struct ath10k *ar)
                                                   svc_to_pipe_map),
                                          &svc_to_pipe_map);
        if (ret != 0) {
-               ath10k_err("Failed to get svc/pipe map: %d\n", ret);
+               ath10k_err(ar, "Failed to get svc/pipe map: %d\n", ret);
                return ret;
        }
 
        if (svc_to_pipe_map == 0) {
                ret = -EIO;
-               ath10k_err("Invalid svc_to_pipe map\n");
+               ath10k_err(ar, "Invalid svc_to_pipe map\n");
                return ret;
        }
 
@@ -1658,7 +1572,7 @@ static int ath10k_pci_init_config(struct ath10k *ar)
                                 target_service_to_ce_map_wlan,
                                 sizeof(target_service_to_ce_map_wlan));
        if (ret != 0) {
-               ath10k_err("Failed to write svc/pipe map: %d\n", ret);
+               ath10k_err(ar, "Failed to write svc/pipe map: %d\n", ret);
                return ret;
        }
 
@@ -1667,18 +1581,17 @@ static int ath10k_pci_init_config(struct ath10k *ar)
                                                   config_flags),
                                          &pcie_config_flags);
        if (ret != 0) {
-               ath10k_err("Failed to get pcie config_flags: %d\n", ret);
+               ath10k_err(ar, "Failed to get pcie config_flags: %d\n", ret);
                return ret;
        }
 
        pcie_config_flags &= ~PCIE_CONFIG_FLAG_ENABLE_L1;
 
-       ret = ath10k_pci_diag_write_mem(ar, pcie_state_targ_addr +
+       ret = ath10k_pci_diag_write_access(ar, pcie_state_targ_addr +
                                 offsetof(struct pcie_state, config_flags),
-                                &pcie_config_flags,
-                                sizeof(pcie_config_flags));
+                                pcie_config_flags);
        if (ret != 0) {
-               ath10k_err("Failed to write pcie config_flags: %d\n", ret);
+               ath10k_err(ar, "Failed to write pcie config_flags: %d\n", ret);
                return ret;
        }
 
@@ -1687,7 +1600,7 @@ static int ath10k_pci_init_config(struct ath10k *ar)
 
        ret = ath10k_pci_diag_read_access(ar, ealloc_targ_addr, &ealloc_value);
        if (ret != 0) {
-               ath10k_err("Faile to get early alloc val: %d\n", ret);
+               ath10k_err(ar, "Faile to get early alloc val: %d\n", ret);
                return ret;
        }
 
@@ -1699,7 +1612,7 @@ static int ath10k_pci_init_config(struct ath10k *ar)
 
        ret = ath10k_pci_diag_write_access(ar, ealloc_targ_addr, ealloc_value);
        if (ret != 0) {
-               ath10k_err("Failed to set early alloc val: %d\n", ret);
+               ath10k_err(ar, "Failed to set early alloc val: %d\n", ret);
                return ret;
        }
 
@@ -1708,7 +1621,7 @@ static int ath10k_pci_init_config(struct ath10k *ar)
 
        ret = ath10k_pci_diag_read_access(ar, flag2_targ_addr, &flag2_value);
        if (ret != 0) {
-               ath10k_err("Failed to get option val: %d\n", ret);
+               ath10k_err(ar, "Failed to get option val: %d\n", ret);
                return ret;
        }
 
@@ -1716,7 +1629,7 @@ static int ath10k_pci_init_config(struct ath10k *ar)
 
        ret = ath10k_pci_diag_write_access(ar, flag2_targ_addr, flag2_value);
        if (ret != 0) {
-               ath10k_err("Failed to set option val: %d\n", ret);
+               ath10k_err(ar, "Failed to set option val: %d\n", ret);
                return ret;
        }
 
@@ -1730,7 +1643,7 @@ static int ath10k_pci_alloc_ce(struct ath10k *ar)
        for (i = 0; i < CE_COUNT; i++) {
                ret = ath10k_ce_alloc_pipe(ar, i, &host_ce_config_wlan[i]);
                if (ret) {
-                       ath10k_err("failed to allocate copy engine pipe %d: %d\n",
+                       ath10k_err(ar, "failed to allocate copy engine pipe %d: %d\n",
                                   i, ret);
                        return ret;
                }
@@ -1761,9 +1674,11 @@ static int ath10k_pci_ce_init(struct ath10k *ar)
                pipe_info->hif_ce_state = ar;
                attr = &host_ce_config_wlan[pipe_num];
 
-               ret = ath10k_ce_init_pipe(ar, pipe_num, attr);
+               ret = ath10k_ce_init_pipe(ar, pipe_num, attr,
+                                         ath10k_pci_ce_send_done,
+                                         ath10k_pci_ce_recv_data);
                if (ret) {
-                       ath10k_err("failed to initialize copy engine pipe %d: %d\n",
+                       ath10k_err(ar, "failed to initialize copy engine pipe %d: %d\n",
                                   pipe_num, ret);
                        return ret;
                }
@@ -1783,32 +1698,19 @@ static int ath10k_pci_ce_init(struct ath10k *ar)
        return 0;
 }
 
-static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar)
+static bool ath10k_pci_has_fw_crashed(struct ath10k *ar)
 {
-       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       u32 fw_indicator;
-
-       ath10k_pci_wake(ar);
-
-       fw_indicator = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS);
-
-       if (fw_indicator & FW_IND_EVENT_PENDING) {
-               /* ACK: clear Target-side pending event */
-               ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS,
-                                  fw_indicator & ~FW_IND_EVENT_PENDING);
+       return ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS) &
+              FW_IND_EVENT_PENDING;
+}
 
-               if (ar_pci->started) {
-                       ath10k_pci_hif_dump_area(ar);
-               } else {
-                       /*
-                        * Probable Target failure before we're prepared
-                        * to handle it.  Generally unexpected.
-                        */
-                       ath10k_warn("early firmware event indicated\n");
-               }
-       }
+static void ath10k_pci_fw_crashed_clear(struct ath10k *ar)
+{
+       u32 val;
 
-       ath10k_pci_sleep(ar);
+       val = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS);
+       val &= ~FW_IND_EVENT_PENDING;
+       ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, val);
 }
 
 /* this function effectively clears target memory controller assert line */
@@ -1833,25 +1735,19 @@ static void ath10k_pci_warm_reset_si0(struct ath10k *ar)
 
 static int ath10k_pci_warm_reset(struct ath10k *ar)
 {
-       int ret = 0;
        u32 val;
 
-       ath10k_dbg(ATH10K_DBG_BOOT, "boot warm reset\n");
-
-       ret = ath10k_do_pci_wake(ar);
-       if (ret) {
-               ath10k_err("failed to wake up target: %d\n", ret);
-               return ret;
-       }
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot warm reset\n");
 
        /* debug */
        val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
                                PCIE_INTR_CAUSE_ADDRESS);
-       ath10k_dbg(ATH10K_DBG_BOOT, "boot host cpu intr cause: 0x%08x\n", val);
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot host cpu intr cause: 0x%08x\n",
+                  val);
 
        val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
                                CPU_INTR_ADDRESS);
-       ath10k_dbg(ATH10K_DBG_BOOT, "boot target cpu intr cause: 0x%08x\n",
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot target cpu intr cause: 0x%08x\n",
                   val);
 
        /* disable pending irqs */
@@ -1894,11 +1790,12 @@ static int ath10k_pci_warm_reset(struct ath10k *ar)
        /* debug */
        val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
                                PCIE_INTR_CAUSE_ADDRESS);
-       ath10k_dbg(ATH10K_DBG_BOOT, "boot host cpu intr cause: 0x%08x\n", val);
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot host cpu intr cause: 0x%08x\n",
+                  val);
 
        val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
                                CPU_INTR_ADDRESS);
-       ath10k_dbg(ATH10K_DBG_BOOT, "boot target cpu intr cause: 0x%08x\n",
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot target cpu intr cause: 0x%08x\n",
                   val);
 
        /* CPU warm reset */
@@ -1909,20 +1806,18 @@ static int ath10k_pci_warm_reset(struct ath10k *ar)
 
        val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS +
                                SOC_RESET_CONTROL_ADDRESS);
-       ath10k_dbg(ATH10K_DBG_BOOT, "boot target reset state: 0x%08x\n", val);
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot target reset state: 0x%08x\n",
+                  val);
 
        msleep(100);
 
-       ath10k_dbg(ATH10K_DBG_BOOT, "boot warm reset complete\n");
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot warm reset complete\n");
 
-       ath10k_do_pci_sleep(ar);
-       return ret;
+       return 0;
 }
 
 static int __ath10k_pci_hif_power_up(struct ath10k *ar, bool cold_reset)
 {
-       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       const char *irq_mode;
        int ret;
 
        /*
@@ -1941,80 +1836,39 @@ static int __ath10k_pci_hif_power_up(struct ath10k *ar, bool cold_reset)
                ret = ath10k_pci_warm_reset(ar);
 
        if (ret) {
-               ath10k_err("failed to reset target: %d\n", ret);
+               ath10k_err(ar, "failed to reset target: %d\n", ret);
                goto err;
        }
 
-       if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
-               /* Force AWAKE forever */
-               ath10k_do_pci_wake(ar);
-
        ret = ath10k_pci_ce_init(ar);
        if (ret) {
-               ath10k_err("failed to initialize CE: %d\n", ret);
-               goto err_ps;
-       }
-
-       ret = ath10k_ce_disable_interrupts(ar);
-       if (ret) {
-               ath10k_err("failed to disable CE interrupts: %d\n", ret);
-               goto err_ce;
-       }
-
-       ret = ath10k_pci_init_irq(ar);
-       if (ret) {
-               ath10k_err("failed to init irqs: %d\n", ret);
-               goto err_ce;
-       }
-
-       ret = ath10k_pci_request_early_irq(ar);
-       if (ret) {
-               ath10k_err("failed to request early irq: %d\n", ret);
-               goto err_deinit_irq;
+               ath10k_err(ar, "failed to initialize CE: %d\n", ret);
+               goto err;
        }
 
        ret = ath10k_pci_wait_for_target_init(ar);
        if (ret) {
-               ath10k_err("failed to wait for target to init: %d\n", ret);
-               goto err_free_early_irq;
+               ath10k_err(ar, "failed to wait for target to init: %d\n", ret);
+               goto err_ce;
        }
 
        ret = ath10k_pci_init_config(ar);
        if (ret) {
-               ath10k_err("failed to setup init config: %d\n", ret);
-               goto err_free_early_irq;
+               ath10k_err(ar, "failed to setup init config: %d\n", ret);
+               goto err_ce;
        }
 
        ret = ath10k_pci_wake_target_cpu(ar);
        if (ret) {
-               ath10k_err("could not wake up target CPU: %d\n", ret);
-               goto err_free_early_irq;
+               ath10k_err(ar, "could not wake up target CPU: %d\n", ret);
+               goto err_ce;
        }
 
-       if (ar_pci->num_msi_intrs > 1)
-               irq_mode = "MSI-X";
-       else if (ar_pci->num_msi_intrs == 1)
-               irq_mode = "MSI";
-       else
-               irq_mode = "legacy";
-
-       if (!test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags))
-               ath10k_info("pci irq %s irq_mode %d reset_mode %d\n",
-                           irq_mode, ath10k_pci_irq_mode,
-                           ath10k_pci_reset_mode);
-
        return 0;
 
-err_free_early_irq:
-       ath10k_pci_free_early_irq(ar);
-err_deinit_irq:
-       ath10k_pci_deinit_irq(ar);
 err_ce:
        ath10k_pci_ce_deinit(ar);
        ath10k_pci_warm_reset(ar);
-err_ps:
-       if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
-               ath10k_do_pci_sleep(ar);
 err:
        return ret;
 }
@@ -2034,7 +1888,7 @@ static int ath10k_pci_hif_power_up_warm(struct ath10k *ar)
                if (ret == 0)
                        break;
 
-               ath10k_warn("failed to warm reset (attempt %d out of %d): %d\n",
+               ath10k_warn(ar, "failed to warm reset (attempt %d out of %d): %d\n",
                            i + 1, ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS, ret);
        }
 
@@ -2045,7 +1899,7 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
 {
        int ret;
 
-       ath10k_dbg(ATH10K_DBG_BOOT, "boot hif power up\n");
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power up\n");
 
        /*
         * Hardware CUS232 version 2 has some issues with cold reset and the
@@ -2057,17 +1911,17 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
         */
        ret = ath10k_pci_hif_power_up_warm(ar);
        if (ret) {
-               ath10k_warn("failed to power up target using warm reset: %d\n",
+               ath10k_warn(ar, "failed to power up target using warm reset: %d\n",
                            ret);
 
                if (ath10k_pci_reset_mode == ATH10K_PCI_RESET_WARM_ONLY)
                        return ret;
 
-               ath10k_warn("trying cold reset\n");
+               ath10k_warn(ar, "trying cold reset\n");
 
                ret = __ath10k_pci_hif_power_up(ar, true);
                if (ret) {
-                       ath10k_err("failed to power up target using cold reset too (%d)\n",
+                       ath10k_err(ar, "failed to power up target using cold reset too (%d)\n",
                                   ret);
                        return ret;
                }
@@ -2078,18 +1932,9 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
 
 static void ath10k_pci_hif_power_down(struct ath10k *ar)
 {
-       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-
-       ath10k_dbg(ATH10K_DBG_BOOT, "boot hif power down\n");
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power down\n");
 
-       ath10k_pci_free_early_irq(ar);
-       ath10k_pci_kill_tasklet(ar);
-       ath10k_pci_deinit_irq(ar);
-       ath10k_pci_ce_deinit(ar);
        ath10k_pci_warm_reset(ar);
-
-       if (!test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
-               ath10k_do_pci_sleep(ar);
 }
 
 #ifdef CONFIG_PM
@@ -2171,7 +2016,13 @@ static void ath10k_msi_err_tasklet(unsigned long data)
 {
        struct ath10k *ar = (struct ath10k *)data;
 
-       ath10k_pci_fw_interrupt_handler(ar);
+       if (!ath10k_pci_has_fw_crashed(ar)) {
+               ath10k_warn(ar, "received unsolicited fw crash interrupt\n");
+               return;
+       }
+
+       ath10k_pci_fw_crashed_clear(ar);
+       ath10k_pci_fw_crashed_dump(ar);
 }
 
 /*
@@ -2185,7 +2036,8 @@ static irqreturn_t ath10k_pci_per_engine_handler(int irq, void *arg)
        int ce_id = irq - ar_pci->pdev->irq - MSI_ASSIGN_CE_INITIAL;
 
        if (ce_id < 0 || ce_id >= ARRAY_SIZE(ar_pci->pipe_info)) {
-               ath10k_warn("unexpected/invalid irq %d ce_id %d\n", irq, ce_id);
+               ath10k_warn(ar, "unexpected/invalid irq %d ce_id %d\n", irq,
+                           ce_id);
                return IRQ_HANDLED;
        }
 
@@ -2232,36 +2084,17 @@ static irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg)
        return IRQ_HANDLED;
 }
 
-static void ath10k_pci_early_irq_tasklet(unsigned long data)
+static void ath10k_pci_tasklet(unsigned long data)
 {
        struct ath10k *ar = (struct ath10k *)data;
-       u32 fw_ind;
-       int ret;
+       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 
-       ret = ath10k_pci_wake(ar);
-       if (ret) {
-               ath10k_warn("failed to wake target in early irq tasklet: %d\n",
-                           ret);
+       if (ath10k_pci_has_fw_crashed(ar)) {
+               ath10k_pci_fw_crashed_clear(ar);
+               ath10k_pci_fw_crashed_dump(ar);
                return;
        }
 
-       fw_ind = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS);
-       if (fw_ind & FW_IND_EVENT_PENDING) {
-               ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS,
-                                  fw_ind & ~FW_IND_EVENT_PENDING);
-               ath10k_pci_hif_dump_area(ar);
-       }
-
-       ath10k_pci_sleep(ar);
-       ath10k_pci_enable_legacy_irq(ar);
-}
-
-static void ath10k_pci_tasklet(unsigned long data)
-{
-       struct ath10k *ar = (struct ath10k *)data;
-       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-
-       ath10k_pci_fw_interrupt_handler(ar); /* FIXME: Handle FW error */
        ath10k_ce_per_engine_service_any(ar);
 
        /* Re-enable legacy irq that was disabled in the irq handler */
@@ -2278,7 +2111,7 @@ static int ath10k_pci_request_irq_msix(struct ath10k *ar)
                          ath10k_pci_msi_fw_handler,
                          IRQF_SHARED, "ath10k_pci", ar);
        if (ret) {
-               ath10k_warn("failed to request MSI-X fw irq %d: %d\n",
+               ath10k_warn(ar, "failed to request MSI-X fw irq %d: %d\n",
                            ar_pci->pdev->irq + MSI_ASSIGN_FW, ret);
                return ret;
        }
@@ -2288,7 +2121,7 @@ static int ath10k_pci_request_irq_msix(struct ath10k *ar)
                                  ath10k_pci_per_engine_handler,
                                  IRQF_SHARED, "ath10k_pci", ar);
                if (ret) {
-                       ath10k_warn("failed to request MSI-X ce irq %d: %d\n",
+                       ath10k_warn(ar, "failed to request MSI-X ce irq %d: %d\n",
                                    ar_pci->pdev->irq + i, ret);
 
                        for (i--; i >= MSI_ASSIGN_CE_INITIAL; i--)
@@ -2311,7 +2144,7 @@ static int ath10k_pci_request_irq_msi(struct ath10k *ar)
                          ath10k_pci_interrupt_handler,
                          IRQF_SHARED, "ath10k_pci", ar);
        if (ret) {
-               ath10k_warn("failed to request MSI irq %d: %d\n",
+               ath10k_warn(ar, "failed to request MSI irq %d: %d\n",
                            ar_pci->pdev->irq, ret);
                return ret;
        }
@@ -2328,7 +2161,7 @@ static int ath10k_pci_request_irq_legacy(struct ath10k *ar)
                          ath10k_pci_interrupt_handler,
                          IRQF_SHARED, "ath10k_pci", ar);
        if (ret) {
-               ath10k_warn("failed to request legacy irq %d: %d\n",
+               ath10k_warn(ar, "failed to request legacy irq %d: %d\n",
                            ar_pci->pdev->irq, ret);
                return ret;
        }
@@ -2349,7 +2182,7 @@ static int ath10k_pci_request_irq(struct ath10k *ar)
                return ath10k_pci_request_irq_msix(ar);
        }
 
-       ath10k_warn("unknown irq configuration upon request\n");
+       ath10k_warn(ar, "unknown irq configuration upon request\n");
        return -EINVAL;
 }
 
@@ -2372,8 +2205,6 @@ static void ath10k_pci_init_irq_tasklets(struct ath10k *ar)
        tasklet_init(&ar_pci->intr_tq, ath10k_pci_tasklet, (unsigned long)ar);
        tasklet_init(&ar_pci->msi_fw_err, ath10k_msi_err_tasklet,
                     (unsigned long)ar);
-       tasklet_init(&ar_pci->early_irq_tasklet, ath10k_pci_early_irq_tasklet,
-                    (unsigned long)ar);
 
        for (i = 0; i < CE_COUNT; i++) {
                ar_pci->pipe_info[i].ar_pci = ar_pci;
@@ -2385,18 +2216,16 @@ static void ath10k_pci_init_irq_tasklets(struct ath10k *ar)
 static int ath10k_pci_init_irq(struct ath10k *ar)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       bool msix_supported = test_bit(ATH10K_PCI_FEATURE_MSI_X,
-                                      ar_pci->features);
        int ret;
 
        ath10k_pci_init_irq_tasklets(ar);
 
-       if (ath10k_pci_irq_mode != ATH10K_PCI_IRQ_AUTO &&
-           !test_bit(ATH10K_FLAG_FIRST_BOOT_DONE, &ar->dev_flags))
-               ath10k_info("limiting irq mode to: %d\n", ath10k_pci_irq_mode);
+       if (ath10k_pci_irq_mode != ATH10K_PCI_IRQ_AUTO)
+               ath10k_info(ar, "limiting irq mode to: %d\n",
+                           ath10k_pci_irq_mode);
 
        /* Try MSI-X */
-       if (ath10k_pci_irq_mode == ATH10K_PCI_IRQ_AUTO && msix_supported) {
+       if (ath10k_pci_irq_mode == ATH10K_PCI_IRQ_AUTO) {
                ar_pci->num_msi_intrs = MSI_NUM_REQUEST;
                ret = pci_enable_msi_range(ar_pci->pdev, ar_pci->num_msi_intrs,
                                                         ar_pci->num_msi_intrs);
@@ -2426,34 +2255,16 @@ static int ath10k_pci_init_irq(struct ath10k *ar)
         * synchronization checking. */
        ar_pci->num_msi_intrs = 0;
 
-       ret = ath10k_pci_wake(ar);
-       if (ret) {
-               ath10k_warn("failed to wake target: %d\n", ret);
-               return ret;
-       }
-
        ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS,
                           PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL);
-       ath10k_pci_sleep(ar);
 
        return 0;
 }
 
-static int ath10k_pci_deinit_irq_legacy(struct ath10k *ar)
+static void ath10k_pci_deinit_irq_legacy(struct ath10k *ar)
 {
-       int ret;
-
-       ret = ath10k_pci_wake(ar);
-       if (ret) {
-               ath10k_warn("failed to wake target: %d\n", ret);
-               return ret;
-       }
-
        ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS,
                           0);
-       ath10k_pci_sleep(ar);
-
-       return 0;
 }
 
 static int ath10k_pci_deinit_irq(struct ath10k *ar)
@@ -2462,7 +2273,8 @@ static int ath10k_pci_deinit_irq(struct ath10k *ar)
 
        switch (ar_pci->num_msi_intrs) {
        case 0:
-               return ath10k_pci_deinit_irq_legacy(ar);
+               ath10k_pci_deinit_irq_legacy(ar);
+               return 0;
        case 1:
                /* fall-through */
        case MSI_NUM_REQUEST:
@@ -2472,7 +2284,7 @@ static int ath10k_pci_deinit_irq(struct ath10k *ar)
                pci_disable_msi(ar_pci->pdev);
        }
 
-       ath10k_warn("unknown irq configuration upon deinit\n");
+       ath10k_warn(ar, "unknown irq configuration upon deinit\n");
        return -EINVAL;
 }
 
@@ -2480,23 +2292,17 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
        unsigned long timeout;
-       int ret;
        u32 val;
 
-       ath10k_dbg(ATH10K_DBG_BOOT, "boot waiting target to initialise\n");
-
-       ret = ath10k_pci_wake(ar);
-       if (ret) {
-               ath10k_err("failed to wake up target for init: %d\n", ret);
-               return ret;
-       }
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot waiting target to initialise\n");
 
        timeout = jiffies + msecs_to_jiffies(ATH10K_PCI_TARGET_WAIT);
 
        do {
                val = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS);
 
-               ath10k_dbg(ATH10K_DBG_BOOT, "boot target indicator %x\n", val);
+               ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot target indicator %x\n",
+                          val);
 
                /* target should never return this */
                if (val == 0xffffffff)
@@ -2511,55 +2317,42 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar)
 
                if (ar_pci->num_msi_intrs == 0)
                        /* Fix potential race by repeating CORE_BASE writes */
-                       ath10k_pci_soc_write32(ar, PCIE_INTR_ENABLE_ADDRESS,
-                                              PCIE_INTR_FIRMWARE_MASK |
-                                              PCIE_INTR_CE_MASK_ALL);
+                       ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS +
+                                          PCIE_INTR_ENABLE_ADDRESS,
+                                          PCIE_INTR_FIRMWARE_MASK |
+                                          PCIE_INTR_CE_MASK_ALL);
 
                mdelay(10);
        } while (time_before(jiffies, timeout));
 
        if (val == 0xffffffff) {
-               ath10k_err("failed to read device register, device is gone\n");
-               ret = -EIO;
-               goto out;
+               ath10k_err(ar, "failed to read device register, device is gone\n");
+               return -EIO;
        }
 
        if (val & FW_IND_EVENT_PENDING) {
-               ath10k_warn("device has crashed during init\n");
-               ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS,
-                                  val & ~FW_IND_EVENT_PENDING);
-               ath10k_pci_hif_dump_area(ar);
-               ret = -ECOMM;
-               goto out;
+               ath10k_warn(ar, "device has crashed during init\n");
+               ath10k_pci_fw_crashed_clear(ar);
+               ath10k_pci_fw_crashed_dump(ar);
+               return -ECOMM;
        }
 
        if (!(val & FW_IND_INITIALIZED)) {
-               ath10k_err("failed to receive initialized event from target: %08x\n",
+               ath10k_err(ar, "failed to receive initialized event from target: %08x\n",
                           val);
-               ret = -ETIMEDOUT;
-               goto out;
+               return -ETIMEDOUT;
        }
 
-       ath10k_dbg(ATH10K_DBG_BOOT, "boot target initialised\n");
-
-out:
-       ath10k_pci_sleep(ar);
-       return ret;
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot target initialised\n");
+       return 0;
 }
 
 static int ath10k_pci_cold_reset(struct ath10k *ar)
 {
-       int i, ret;
+       int i;
        u32 val;
 
-       ath10k_dbg(ATH10K_DBG_BOOT, "boot cold reset\n");
-
-       ret = ath10k_do_pci_wake(ar);
-       if (ret) {
-               ath10k_err("failed to wake up target: %d\n",
-                          ret);
-               return ret;
-       }
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cold reset\n");
 
        /* Put Target, including PCIe, into RESET. */
        val = ath10k_pci_reg_read32(ar, SOC_GLOBAL_RESET_ADDRESS);
@@ -2584,169 +2377,198 @@ static int ath10k_pci_cold_reset(struct ath10k *ar)
                msleep(1);
        }
 
-       ath10k_do_pci_sleep(ar);
-
-       ath10k_dbg(ATH10K_DBG_BOOT, "boot cold reset complete\n");
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cold reset complete\n");
 
        return 0;
 }
 
-static void ath10k_pci_dump_features(struct ath10k_pci *ar_pci)
-{
-       int i;
-
-       for (i = 0; i < ATH10K_PCI_FEATURE_COUNT; i++) {
-               if (!test_bit(i, ar_pci->features))
-                       continue;
-
-               switch (i) {
-               case ATH10K_PCI_FEATURE_MSI_X:
-                       ath10k_dbg(ATH10K_DBG_BOOT, "device supports MSI-X\n");
-                       break;
-               case ATH10K_PCI_FEATURE_SOC_POWER_SAVE:
-                       ath10k_dbg(ATH10K_DBG_BOOT, "QCA98XX SoC power save enabled\n");
-                       break;
-               }
-       }
-}
-
-static int ath10k_pci_probe(struct pci_dev *pdev,
-                           const struct pci_device_id *pci_dev)
+static int ath10k_pci_claim(struct ath10k *ar)
 {
-       void __iomem *mem;
-       int ret = 0;
-       struct ath10k *ar;
-       struct ath10k_pci *ar_pci;
-       u32 lcr_val, chip_id;
-
-       ath10k_dbg(ATH10K_DBG_PCI, "pci probe\n");
-
-       ar_pci = kzalloc(sizeof(*ar_pci), GFP_KERNEL);
-       if (ar_pci == NULL)
-               return -ENOMEM;
-
-       ar_pci->pdev = pdev;
-       ar_pci->dev = &pdev->dev;
-
-       switch (pci_dev->device) {
-       case QCA988X_2_0_DEVICE_ID:
-               set_bit(ATH10K_PCI_FEATURE_MSI_X, ar_pci->features);
-               break;
-       default:
-               ret = -ENODEV;
-               ath10k_err("Unknown device ID: %d\n", pci_dev->device);
-               goto err_ar_pci;
-       }
-
-       if (ath10k_pci_target_ps)
-               set_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features);
-
-       ath10k_pci_dump_features(ar_pci);
-
-       ar = ath10k_core_create(ar_pci, ar_pci->dev, &ath10k_pci_hif_ops);
-       if (!ar) {
-               ath10k_err("failed to create driver core\n");
-               ret = -EINVAL;
-               goto err_ar_pci;
-       }
-
-       ar_pci->ar = ar;
-       atomic_set(&ar_pci->keep_awake_count, 0);
+       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+       struct pci_dev *pdev = ar_pci->pdev;
+       u32 lcr_val;
+       int ret;
 
        pci_set_drvdata(pdev, ar);
 
        ret = pci_enable_device(pdev);
        if (ret) {
-               ath10k_err("failed to enable PCI device: %d\n", ret);
-               goto err_ar;
+               ath10k_err(ar, "failed to enable pci device: %d\n", ret);
+               return ret;
        }
 
-       /* Request MMIO resources */
        ret = pci_request_region(pdev, BAR_NUM, "ath");
        if (ret) {
-               ath10k_err("failed to request MMIO region: %d\n", ret);
+               ath10k_err(ar, "failed to request region BAR%d: %d\n", BAR_NUM,
+                          ret);
                goto err_device;
        }
 
-       /*
-        * Target structures have a limit of 32 bit DMA pointers.
-        * DMA pointers can be wider than 32 bits by default on some systems.
-        */
+       /* Target expects 32 bit DMA. Enforce it. */
        ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
        if (ret) {
-               ath10k_err("failed to set DMA mask to 32-bit: %d\n", ret);
+               ath10k_err(ar, "failed to set dma mask to 32-bit: %d\n", ret);
                goto err_region;
        }
 
        ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
        if (ret) {
-               ath10k_err("failed to set consistent DMA mask to 32-bit\n");
+               ath10k_err(ar, "failed to set consistent dma mask to 32-bit: %d\n",
+                          ret);
                goto err_region;
        }
 
-       /* Set bus master bit in PCI_COMMAND to enable DMA */
        pci_set_master(pdev);
 
-       /*
-        * Temporary FIX: disable ASPM
-        * Will be removed after the OTP is programmed
-        */
+       /* Workaround: Disable ASPM */
        pci_read_config_dword(pdev, 0x80, &lcr_val);
        pci_write_config_dword(pdev, 0x80, (lcr_val & 0xffffff00));
 
        /* Arrange for access to Target SoC registers. */
-       mem = pci_iomap(pdev, BAR_NUM, 0);
-       if (!mem) {
-               ath10k_err("failed to perform IOMAP for BAR%d\n", BAR_NUM);
+       ar_pci->mem = pci_iomap(pdev, BAR_NUM, 0);
+       if (!ar_pci->mem) {
+               ath10k_err(ar, "failed to iomap BAR%d\n", BAR_NUM);
                ret = -EIO;
                goto err_master;
        }
 
-       ar_pci->mem = mem;
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot pci_mem 0x%p\n", ar_pci->mem);
+       return 0;
+
+err_master:
+       pci_clear_master(pdev);
+
+err_region:
+       pci_release_region(pdev, BAR_NUM);
+
+err_device:
+       pci_disable_device(pdev);
+
+       return ret;
+}
+
+static void ath10k_pci_release(struct ath10k *ar)
+{
+       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+       struct pci_dev *pdev = ar_pci->pdev;
+
+       pci_iounmap(pdev, ar_pci->mem);
+       pci_release_region(pdev, BAR_NUM);
+       pci_clear_master(pdev);
+       pci_disable_device(pdev);
+}
+
+static int ath10k_pci_probe(struct pci_dev *pdev,
+                           const struct pci_device_id *pci_dev)
+{
+       int ret = 0;
+       struct ath10k *ar;
+       struct ath10k_pci *ar_pci;
+       u32 chip_id;
+
+       ar = ath10k_core_create(sizeof(*ar_pci), &pdev->dev,
+                               &ath10k_pci_hif_ops);
+       if (!ar) {
+               dev_err(&pdev->dev, "failed to allocate core\n");
+               return -ENOMEM;
+       }
+
+       ath10k_dbg(ar, ATH10K_DBG_PCI, "pci probe\n");
+
+       ar_pci = ath10k_pci_priv(ar);
+       ar_pci->pdev = pdev;
+       ar_pci->dev = &pdev->dev;
+       ar_pci->ar = ar;
 
        spin_lock_init(&ar_pci->ce_lock);
+       setup_timer(&ar_pci->rx_post_retry, ath10k_pci_rx_replenish_retry,
+                   (unsigned long)ar);
 
-       ret = ath10k_do_pci_wake(ar);
+       ret = ath10k_pci_claim(ar);
        if (ret) {
-               ath10k_err("Failed to get chip id: %d\n", ret);
-               goto err_iomap;
+               ath10k_err(ar, "failed to claim device: %d\n", ret);
+               goto err_core_destroy;
        }
 
-       chip_id = ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS);
+       ret = ath10k_pci_wake(ar);
+       if (ret) {
+               ath10k_err(ar, "failed to wake up: %d\n", ret);
+               goto err_release;
+       }
 
-       ath10k_do_pci_sleep(ar);
+       chip_id = ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS);
+       if (chip_id == 0xffffffff) {
+               ath10k_err(ar, "failed to get chip id\n");
+               goto err_sleep;
+       }
 
        ret = ath10k_pci_alloc_ce(ar);
        if (ret) {
-               ath10k_err("failed to allocate copy engine pipes: %d\n", ret);
-               goto err_iomap;
+               ath10k_err(ar, "failed to allocate copy engine pipes: %d\n",
+                          ret);
+               goto err_sleep;
+       }
+
+       ath10k_pci_ce_deinit(ar);
+
+       ret = ath10k_ce_disable_interrupts(ar);
+       if (ret) {
+               ath10k_err(ar, "failed to disable copy engine interrupts: %d\n",
+                          ret);
+               goto err_free_ce;
        }
 
-       ath10k_dbg(ATH10K_DBG_BOOT, "boot pci_mem 0x%p\n", ar_pci->mem);
+       /* Workaround: There's no known way to mask all possible interrupts via
+        * device CSR. The only way to make sure device doesn't assert
+        * interrupts is to reset it. Interrupts are then disabled on host
+        * after handlers are registered.
+        */
+       ath10k_pci_warm_reset(ar);
 
-       ret = ath10k_core_register(ar, chip_id);
+       ret = ath10k_pci_init_irq(ar);
        if (ret) {
-               ath10k_err("failed to register driver core: %d\n", ret);
+               ath10k_err(ar, "failed to init irqs: %d\n", ret);
                goto err_free_ce;
        }
 
+       ath10k_info(ar, "pci irq %s interrupts %d irq_mode %d reset_mode %d\n",
+                   ath10k_pci_get_irq_method(ar), ar_pci->num_msi_intrs,
+                   ath10k_pci_irq_mode, ath10k_pci_reset_mode);
+
+       ret = ath10k_pci_request_irq(ar);
+       if (ret) {
+               ath10k_warn(ar, "failed to request irqs: %d\n", ret);
+               goto err_deinit_irq;
+       }
+
+       /* This shouldn't race as the device has been reset above. */
+       ath10k_pci_irq_disable(ar);
+
+       ret = ath10k_core_register(ar, chip_id);
+       if (ret) {
+               ath10k_err(ar, "failed to register driver core: %d\n", ret);
+               goto err_free_irq;
+       }
+
        return 0;
 
+err_free_irq:
+       ath10k_pci_free_irq(ar);
+
+err_deinit_irq:
+       ath10k_pci_deinit_irq(ar);
+
 err_free_ce:
        ath10k_pci_free_ce(ar);
-err_iomap:
-       pci_iounmap(pdev, mem);
-err_master:
-       pci_clear_master(pdev);
-err_region:
-       pci_release_region(pdev, BAR_NUM);
-err_device:
-       pci_disable_device(pdev);
-err_ar:
+
+err_sleep:
+       ath10k_pci_sleep(ar);
+
+err_release:
+       ath10k_pci_release(ar);
+
+err_core_destroy:
        ath10k_core_destroy(ar);
-err_ar_pci:
-       /* call HIF PCI free here */
-       kfree(ar_pci);
 
        return ret;
 }
@@ -2756,7 +2578,7 @@ static void ath10k_pci_remove(struct pci_dev *pdev)
        struct ath10k *ar = pci_get_drvdata(pdev);
        struct ath10k_pci *ar_pci;
 
-       ath10k_dbg(ATH10K_DBG_PCI, "pci remove\n");
+       ath10k_dbg(ar, ATH10K_DBG_PCI, "pci remove\n");
 
        if (!ar)
                return;
@@ -2767,15 +2589,13 @@ static void ath10k_pci_remove(struct pci_dev *pdev)
                return;
 
        ath10k_core_unregister(ar);
+       ath10k_pci_free_irq(ar);
+       ath10k_pci_deinit_irq(ar);
+       ath10k_pci_ce_deinit(ar);
        ath10k_pci_free_ce(ar);
-
-       pci_iounmap(pdev, ar_pci->mem);
-       pci_release_region(pdev, BAR_NUM);
-       pci_clear_master(pdev);
-       pci_disable_device(pdev);
-
+       ath10k_pci_sleep(ar);
+       ath10k_pci_release(ar);
        ath10k_core_destroy(ar);
-       kfree(ar_pci);
 }
 
 MODULE_DEVICE_TABLE(pci, ath10k_pci_id_table);
@@ -2793,7 +2613,8 @@ static int __init ath10k_pci_init(void)
 
        ret = pci_register_driver(&ath10k_pci_driver);
        if (ret)
-               ath10k_err("failed to register PCI driver: %d\n", ret);
+               printk(KERN_ERR "failed to register ath10k pci driver: %d\n",
+                      ret);
 
        return ret;
 }
@@ -2809,5 +2630,5 @@ module_exit(ath10k_pci_exit);
 MODULE_AUTHOR("Qualcomm Atheros");
 MODULE_DESCRIPTION("Driver support for Atheros QCA988X PCIe devices");
 MODULE_LICENSE("Dual BSD/GPL");
-MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_FW_2_FILE);
+MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_FW_3_FILE);
 MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_BOARD_DATA_FILE);
index 940129209990337a1a99f79599014abc48b6b605..cf36511c7f4dcf41db9610b5cd9487cefcfc59ad 100644 (file)
@@ -23,9 +23,6 @@
 #include "hw.h"
 #include "ce.h"
 
-/* FW dump area */
-#define REG_DUMP_COUNT_QCA988X 60
-
 /*
  * maximum number of bytes that can be handled atomically by DiagRead/DiagWrite
  */
@@ -103,12 +100,12 @@ struct pcie_state {
  * NOTE: Structure is shared between Host software and Target firmware!
  */
 struct ce_pipe_config {
-       u32 pipenum;
-       u32 pipedir;
-       u32 nentries;
-       u32 nbytes_max;
-       u32 flags;
-       u32 reserved;
+       __le32 pipenum;
+       __le32 pipedir;
+       __le32 nentries;
+       __le32 nbytes_max;
+       __le32 flags;
+       __le32 reserved;
 };
 
 /*
@@ -130,17 +127,9 @@ struct ce_pipe_config {
 
 /* Establish a mapping between a service/direction and a pipe. */
 struct service_to_pipe {
-       u32 service_id;
-       u32 pipedir;
-       u32 pipenum;
-};
-
-enum ath10k_pci_features {
-       ATH10K_PCI_FEATURE_MSI_X                = 0,
-       ATH10K_PCI_FEATURE_SOC_POWER_SAVE       = 1,
-
-       /* keep last */
-       ATH10K_PCI_FEATURE_COUNT
+       __le32 service_id;
+       __le32 pipedir;
+       __le32 pipenum;
 };
 
 /* Per-pipe state. */
@@ -169,8 +158,6 @@ struct ath10k_pci {
        struct ath10k *ar;
        void __iomem *mem;
 
-       DECLARE_BITMAP(features, ATH10K_PCI_FEATURE_COUNT);
-
        /*
         * Number of MSI interrupts granted, 0 --> using legacy PCI line
         * interrupts.
@@ -179,12 +166,6 @@ struct ath10k_pci {
 
        struct tasklet_struct intr_tq;
        struct tasklet_struct msi_fw_err;
-       struct tasklet_struct early_irq_tasklet;
-
-       int started;
-
-       atomic_t keep_awake_count;
-       bool verified_awake;
 
        struct ath10k_pci_pipe pipe_info[CE_COUNT_MAX];
 
@@ -198,27 +179,15 @@ struct ath10k_pci {
 
        /* Map CE id to ce_state */
        struct ath10k_ce_pipe ce_states[CE_COUNT_MAX];
+       struct timer_list rx_post_retry;
 };
 
 static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar)
 {
-       return ar->hif.priv;
-}
-
-static inline u32 ath10k_pci_reg_read32(struct ath10k *ar, u32 addr)
-{
-       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-
-       return ioread32(ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr);
-}
-
-static inline void ath10k_pci_reg_write32(struct ath10k *ar, u32 addr, u32 val)
-{
-       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-
-       iowrite32(val, ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr);
+       return (struct ath10k_pci *)ar->drv_priv;
 }
 
+#define ATH10K_PCI_RX_POST_RETRY_MS 50
 #define ATH_PCI_RESET_WAIT_MAX 10 /* ms */
 #define PCIE_WAKE_TIMEOUT 5000 /* 5ms */
 
@@ -242,35 +211,17 @@ static inline void ath10k_pci_reg_write32(struct ath10k *ar, u32 addr, u32 val)
 /* Wait up to this many Ms for a Diagnostic Access CE operation to complete */
 #define DIAG_ACCESS_CE_TIMEOUT_MS 10
 
-/*
- * This API allows the Host to access Target registers directly
- * and relatively efficiently over PCIe.
- * This allows the Host to avoid extra overhead associated with
- * sending a message to firmware and waiting for a response message
- * from firmware, as is done on other interconnects.
- *
- * Yet there is some complexity with direct accesses because the
- * Target's power state is not known a priori. The Host must issue
- * special PCIe reads/writes in order to explicitly wake the Target
- * and to verify that it is awake and will remain awake.
- *
- * Usage:
+/* Target exposes its registers for direct access. However before host can
+ * access them it needs to make sure the target is awake (ath10k_pci_wake,
+ * ath10k_pci_wake_wait, ath10k_pci_is_awake). Once target is awake it won't go
+ * to sleep unless host tells it to (ath10k_pci_sleep).
  *
- *   Use ath10k_pci_read32 and ath10k_pci_write32 to access Target space.
- *   These calls must be bracketed by ath10k_pci_wake and
- *   ath10k_pci_sleep.  A single BEGIN/END pair is adequate for
- *   multiple READ/WRITE operations.
+ * If host tries to access target registers without waking it up it can
+ * scribble over host memory.
  *
- *   Use ath10k_pci_wake to put the Target in a state in
- *   which it is legal for the Host to directly access it. This
- *   may involve waking the Target from a low power state, which
- *   may take up to 2Ms!
- *
- *   Use ath10k_pci_sleep to tell the Target that as far as
- *   this code path is concerned, it no longer needs to remain
- *   directly accessible.  BEGIN/END is under a reference counter;
- *   multiple code paths may issue BEGIN/END on a single targid.
+ * If target is asleep waking it up may take up to even 2ms.
  */
+
 static inline void ath10k_pci_write32(struct ath10k *ar, u32 offset,
                                      u32 value)
 {
@@ -296,25 +247,18 @@ static inline void ath10k_pci_soc_write32(struct ath10k *ar, u32 addr, u32 val)
        ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + addr, val);
 }
 
-int ath10k_do_pci_wake(struct ath10k *ar);
-void ath10k_do_pci_sleep(struct ath10k *ar);
-
-static inline int ath10k_pci_wake(struct ath10k *ar)
+static inline u32 ath10k_pci_reg_read32(struct ath10k *ar, u32 addr)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 
-       if (test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
-               return ath10k_do_pci_wake(ar);
-
-       return 0;
+       return ioread32(ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr);
 }
 
-static inline void ath10k_pci_sleep(struct ath10k *ar)
+static inline void ath10k_pci_reg_write32(struct ath10k *ar, u32 addr, u32 val)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 
-       if (test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
-               ath10k_do_pci_sleep(ar);
+       iowrite32(val, ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr);
 }
 
 #endif /* _PCI_H_ */
diff --git a/drivers/net/wireless/ath/ath10k/spectral.c b/drivers/net/wireless/ath/ath10k/spectral.c
new file mode 100644 (file)
index 0000000..3e1454b
--- /dev/null
@@ -0,0 +1,561 @@
+/*
+ * Copyright (c) 2013 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/relay.h>
+#include "core.h"
+#include "debug.h"
+
+static void send_fft_sample(struct ath10k *ar,
+                           const struct fft_sample_tlv *fft_sample_tlv)
+{
+       int length;
+
+       if (!ar->spectral.rfs_chan_spec_scan)
+               return;
+
+       length = __be16_to_cpu(fft_sample_tlv->length) +
+                sizeof(*fft_sample_tlv);
+       relay_write(ar->spectral.rfs_chan_spec_scan, fft_sample_tlv, length);
+}
+
+static uint8_t get_max_exp(s8 max_index, u16 max_magnitude, size_t bin_len,
+                          u8 *data)
+{
+       int dc_pos;
+       u8 max_exp;
+
+       dc_pos = bin_len / 2;
+
+       /* peak index outside of bins */
+       if (dc_pos < max_index || -dc_pos >= max_index)
+               return 0;
+
+       for (max_exp = 0; max_exp < 8; max_exp++) {
+               if (data[dc_pos + max_index] == (max_magnitude >> max_exp))
+                       break;
+       }
+
+       /* max_exp not found */
+       if (data[dc_pos + max_index] != (max_magnitude >> max_exp))
+               return 0;
+
+       return max_exp;
+}
+
+int ath10k_spectral_process_fft(struct ath10k *ar,
+                               struct wmi_single_phyerr_rx_event *event,
+                               struct phyerr_fft_report *fftr,
+                               size_t bin_len, u64 tsf)
+{
+       struct fft_sample_ath10k *fft_sample;
+       u8 buf[sizeof(*fft_sample) + SPECTRAL_ATH10K_MAX_NUM_BINS];
+       u16 freq1, freq2, total_gain_db, base_pwr_db, length, peak_mag;
+       u32 reg0, reg1, nf_list1, nf_list2;
+       u8 chain_idx, *bins;
+       int dc_pos;
+
+       fft_sample = (struct fft_sample_ath10k *)&buf;
+
+       if (bin_len < 64 || bin_len > SPECTRAL_ATH10K_MAX_NUM_BINS)
+               return -EINVAL;
+
+       reg0 = __le32_to_cpu(fftr->reg0);
+       reg1 = __le32_to_cpu(fftr->reg1);
+
+       length = sizeof(*fft_sample) - sizeof(struct fft_sample_tlv) + bin_len;
+       fft_sample->tlv.type = ATH_FFT_SAMPLE_ATH10K;
+       fft_sample->tlv.length = __cpu_to_be16(length);
+
+       /* TODO: there might be a reason why the hardware reports 20/40/80 MHz,
+        * but the results/plots suggest that its actually 22/44/88 MHz.
+        */
+       switch (event->hdr.chan_width_mhz) {
+       case 20:
+               fft_sample->chan_width_mhz = 22;
+               break;
+       case 40:
+               fft_sample->chan_width_mhz = 44;
+               break;
+       case 80:
+               /* TODO: As experiments with an analogue sender and various
+                * configuaritions (fft-sizes of 64/128/256 and 20/40/80 Mhz)
+                * show, the particular configuration of 80 MHz/64 bins does
+                * not match with the other smaples at all. Until the reason
+                * for that is found, don't report these samples.
+                */
+               if (bin_len == 64)
+                       return -EINVAL;
+               fft_sample->chan_width_mhz = 88;
+               break;
+       default:
+               fft_sample->chan_width_mhz = event->hdr.chan_width_mhz;
+       }
+
+       fft_sample->relpwr_db = MS(reg1, SEARCH_FFT_REPORT_REG1_RELPWR_DB);
+       fft_sample->avgpwr_db = MS(reg1, SEARCH_FFT_REPORT_REG1_AVGPWR_DB);
+
+       peak_mag = MS(reg1, SEARCH_FFT_REPORT_REG1_PEAK_MAG);
+       fft_sample->max_magnitude = __cpu_to_be16(peak_mag);
+       fft_sample->max_index = MS(reg0, SEARCH_FFT_REPORT_REG0_PEAK_SIDX);
+       fft_sample->rssi = event->hdr.rssi_combined;
+
+       total_gain_db = MS(reg0, SEARCH_FFT_REPORT_REG0_TOTAL_GAIN_DB);
+       base_pwr_db = MS(reg0, SEARCH_FFT_REPORT_REG0_BASE_PWR_DB);
+       fft_sample->total_gain_db = __cpu_to_be16(total_gain_db);
+       fft_sample->base_pwr_db = __cpu_to_be16(base_pwr_db);
+
+       freq1 = __le16_to_cpu(event->hdr.freq1);
+       freq2 = __le16_to_cpu(event->hdr.freq2);
+       fft_sample->freq1 = __cpu_to_be16(freq1);
+       fft_sample->freq2 = __cpu_to_be16(freq2);
+
+       nf_list1 = __le32_to_cpu(event->hdr.nf_list_1);
+       nf_list2 = __le32_to_cpu(event->hdr.nf_list_2);
+       chain_idx = MS(reg0, SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX);
+
+       switch (chain_idx) {
+       case 0:
+               fft_sample->noise = __cpu_to_be16(nf_list1 & 0xffffu);
+               break;
+       case 1:
+               fft_sample->noise = __cpu_to_be16((nf_list1 >> 16) & 0xffffu);
+               break;
+       case 2:
+               fft_sample->noise = __cpu_to_be16(nf_list2 & 0xffffu);
+               break;
+       case 3:
+               fft_sample->noise = __cpu_to_be16((nf_list2 >> 16) & 0xffffu);
+               break;
+       }
+
+       bins = (u8 *)fftr;
+       bins += sizeof(*fftr);
+
+       fft_sample->tsf = __cpu_to_be64(tsf);
+
+       /* max_exp has been directly reported by previous hardware (ath9k),
+        * maybe its possible to get it by other means?
+        */
+       fft_sample->max_exp = get_max_exp(fft_sample->max_index, peak_mag,
+                                         bin_len, bins);
+
+       memcpy(fft_sample->data, bins, bin_len);
+
+       /* DC value (value in the middle) is the blind spot of the spectral
+        * sample and invalid, interpolate it.
+        */
+       dc_pos = bin_len / 2;
+       fft_sample->data[dc_pos] = (fft_sample->data[dc_pos + 1] +
+                                   fft_sample->data[dc_pos - 1]) / 2;
+
+       send_fft_sample(ar, &fft_sample->tlv);
+
+       return 0;
+}
+
+static struct ath10k_vif *ath10k_get_spectral_vdev(struct ath10k *ar)
+{
+       struct ath10k_vif *arvif;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       if (list_empty(&ar->arvifs))
+               return NULL;
+
+       /* if there already is a vif doing spectral, return that. */
+       list_for_each_entry(arvif, &ar->arvifs, list)
+               if (arvif->spectral_enabled)
+                       return arvif;
+
+       /* otherwise, return the first vif. */
+       return list_first_entry(&ar->arvifs, typeof(*arvif), list);
+}
+
+static int ath10k_spectral_scan_trigger(struct ath10k *ar)
+{
+       struct ath10k_vif *arvif;
+       int res;
+       int vdev_id;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       arvif = ath10k_get_spectral_vdev(ar);
+       if (!arvif)
+               return -ENODEV;
+       vdev_id = arvif->vdev_id;
+
+       if (ar->spectral.mode == SPECTRAL_DISABLED)
+               return 0;
+
+       res = ath10k_wmi_vdev_spectral_enable(ar, vdev_id,
+                                             WMI_SPECTRAL_TRIGGER_CMD_CLEAR,
+                                             WMI_SPECTRAL_ENABLE_CMD_ENABLE);
+       if (res < 0)
+               return res;
+
+       res = ath10k_wmi_vdev_spectral_enable(ar, vdev_id,
+                                             WMI_SPECTRAL_TRIGGER_CMD_TRIGGER,
+                                             WMI_SPECTRAL_ENABLE_CMD_ENABLE);
+       if (res < 0)
+               return res;
+
+       return 0;
+}
+
+static int ath10k_spectral_scan_config(struct ath10k *ar,
+                                      enum ath10k_spectral_mode mode)
+{
+       struct wmi_vdev_spectral_conf_arg arg;
+       struct ath10k_vif *arvif;
+       int vdev_id, count, res = 0;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       arvif = ath10k_get_spectral_vdev(ar);
+       if (!arvif)
+               return -ENODEV;
+
+       vdev_id = arvif->vdev_id;
+
+       arvif->spectral_enabled = (mode != SPECTRAL_DISABLED);
+       ar->spectral.mode = mode;
+
+       res = ath10k_wmi_vdev_spectral_enable(ar, vdev_id,
+                                             WMI_SPECTRAL_TRIGGER_CMD_CLEAR,
+                                             WMI_SPECTRAL_ENABLE_CMD_DISABLE);
+       if (res < 0) {
+               ath10k_warn(ar, "failed to enable spectral scan: %d\n", res);
+               return res;
+       }
+
+       if (mode == SPECTRAL_DISABLED)
+               return 0;
+
+       if (mode == SPECTRAL_BACKGROUND)
+               count = WMI_SPECTRAL_COUNT_DEFAULT;
+       else
+               count = max_t(u8, 1, ar->spectral.config.count);
+
+       arg.vdev_id = vdev_id;
+       arg.scan_count = count;
+       arg.scan_period = WMI_SPECTRAL_PERIOD_DEFAULT;
+       arg.scan_priority = WMI_SPECTRAL_PRIORITY_DEFAULT;
+       arg.scan_fft_size = ar->spectral.config.fft_size;
+       arg.scan_gc_ena = WMI_SPECTRAL_GC_ENA_DEFAULT;
+       arg.scan_restart_ena = WMI_SPECTRAL_RESTART_ENA_DEFAULT;
+       arg.scan_noise_floor_ref = WMI_SPECTRAL_NOISE_FLOOR_REF_DEFAULT;
+       arg.scan_init_delay = WMI_SPECTRAL_INIT_DELAY_DEFAULT;
+       arg.scan_nb_tone_thr = WMI_SPECTRAL_NB_TONE_THR_DEFAULT;
+       arg.scan_str_bin_thr = WMI_SPECTRAL_STR_BIN_THR_DEFAULT;
+       arg.scan_wb_rpt_mode = WMI_SPECTRAL_WB_RPT_MODE_DEFAULT;
+       arg.scan_rssi_rpt_mode = WMI_SPECTRAL_RSSI_RPT_MODE_DEFAULT;
+       arg.scan_rssi_thr = WMI_SPECTRAL_RSSI_THR_DEFAULT;
+       arg.scan_pwr_format = WMI_SPECTRAL_PWR_FORMAT_DEFAULT;
+       arg.scan_rpt_mode = WMI_SPECTRAL_RPT_MODE_DEFAULT;
+       arg.scan_bin_scale = WMI_SPECTRAL_BIN_SCALE_DEFAULT;
+       arg.scan_dbm_adj = WMI_SPECTRAL_DBM_ADJ_DEFAULT;
+       arg.scan_chn_mask = WMI_SPECTRAL_CHN_MASK_DEFAULT;
+
+       res = ath10k_wmi_vdev_spectral_conf(ar, &arg);
+       if (res < 0) {
+               ath10k_warn(ar, "failed to configure spectral scan: %d\n", res);
+               return res;
+       }
+
+       return 0;
+}
+
+static ssize_t read_file_spec_scan_ctl(struct file *file, char __user *user_buf,
+                                      size_t count, loff_t *ppos)
+{
+       struct ath10k *ar = file->private_data;
+       char *mode = "";
+       unsigned int len;
+       enum ath10k_spectral_mode spectral_mode;
+
+       mutex_lock(&ar->conf_mutex);
+       spectral_mode = ar->spectral.mode;
+       mutex_unlock(&ar->conf_mutex);
+
+       switch (spectral_mode) {
+       case SPECTRAL_DISABLED:
+               mode = "disable";
+               break;
+       case SPECTRAL_BACKGROUND:
+               mode = "background";
+               break;
+       case SPECTRAL_MANUAL:
+               mode = "manual";
+               break;
+       }
+
+       len = strlen(mode);
+       return simple_read_from_buffer(user_buf, count, ppos, mode, len);
+}
+
+static ssize_t write_file_spec_scan_ctl(struct file *file,
+                                       const char __user *user_buf,
+                                       size_t count, loff_t *ppos)
+{
+       struct ath10k *ar = file->private_data;
+       char buf[32];
+       ssize_t len;
+       int res;
+
+       len = min(count, sizeof(buf) - 1);
+       if (copy_from_user(buf, user_buf, len))
+               return -EFAULT;
+
+       buf[len] = '\0';
+
+       mutex_lock(&ar->conf_mutex);
+
+       if (strncmp("trigger", buf, 7) == 0) {
+               if (ar->spectral.mode == SPECTRAL_MANUAL ||
+                   ar->spectral.mode == SPECTRAL_BACKGROUND) {
+                       /* reset the configuration to adopt possibly changed
+                        * debugfs parameters
+                        */
+                       res = ath10k_spectral_scan_config(ar,
+                                                         ar->spectral.mode);
+                       if (res < 0) {
+                               ath10k_warn(ar, "failed to reconfigure spectral scan: %d\n",
+                                           res);
+                       }
+                       res = ath10k_spectral_scan_trigger(ar);
+                       if (res < 0) {
+                               ath10k_warn(ar, "failed to trigger spectral scan: %d\n",
+                                           res);
+                       }
+               } else {
+                       res = -EINVAL;
+               }
+       } else if (strncmp("background", buf, 9) == 0) {
+               res = ath10k_spectral_scan_config(ar, SPECTRAL_BACKGROUND);
+       } else if (strncmp("manual", buf, 6) == 0) {
+               res = ath10k_spectral_scan_config(ar, SPECTRAL_MANUAL);
+       } else if (strncmp("disable", buf, 7) == 0) {
+               res = ath10k_spectral_scan_config(ar, SPECTRAL_DISABLED);
+       } else {
+               res = -EINVAL;
+       }
+
+       mutex_unlock(&ar->conf_mutex);
+
+       if (res < 0)
+               return res;
+
+       return count;
+}
+
+static const struct file_operations fops_spec_scan_ctl = {
+       .read = read_file_spec_scan_ctl,
+       .write = write_file_spec_scan_ctl,
+       .open = simple_open,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
+static ssize_t read_file_spectral_count(struct file *file,
+                                       char __user *user_buf,
+                                       size_t count, loff_t *ppos)
+{
+       struct ath10k *ar = file->private_data;
+       char buf[32];
+       unsigned int len;
+       u8 spectral_count;
+
+       mutex_lock(&ar->conf_mutex);
+       spectral_count = ar->spectral.config.count;
+       mutex_unlock(&ar->conf_mutex);
+
+       len = sprintf(buf, "%d\n", spectral_count);
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_spectral_count(struct file *file,
+                                        const char __user *user_buf,
+                                        size_t count, loff_t *ppos)
+{
+       struct ath10k *ar = file->private_data;
+       unsigned long val;
+       char buf[32];
+       ssize_t len;
+
+       len = min(count, sizeof(buf) - 1);
+       if (copy_from_user(buf, user_buf, len))
+               return -EFAULT;
+
+       buf[len] = '\0';
+       if (kstrtoul(buf, 0, &val))
+               return -EINVAL;
+
+       if (val < 0 || val > 255)
+               return -EINVAL;
+
+       mutex_lock(&ar->conf_mutex);
+       ar->spectral.config.count = val;
+       mutex_unlock(&ar->conf_mutex);
+
+       return count;
+}
+
+static const struct file_operations fops_spectral_count = {
+       .read = read_file_spectral_count,
+       .write = write_file_spectral_count,
+       .open = simple_open,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
+static ssize_t read_file_spectral_bins(struct file *file,
+                                      char __user *user_buf,
+                                      size_t count, loff_t *ppos)
+{
+       struct ath10k *ar = file->private_data;
+       char buf[32];
+       unsigned int len, bins, fft_size, bin_scale;
+
+       mutex_lock(&ar->conf_mutex);
+
+       fft_size = ar->spectral.config.fft_size;
+       bin_scale = WMI_SPECTRAL_BIN_SCALE_DEFAULT;
+       bins = 1 << (fft_size - bin_scale);
+
+       mutex_unlock(&ar->conf_mutex);
+
+       len = sprintf(buf, "%d\n", bins);
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_spectral_bins(struct file *file,
+                                       const char __user *user_buf,
+                                       size_t count, loff_t *ppos)
+{
+       struct ath10k *ar = file->private_data;
+       unsigned long val;
+       char buf[32];
+       ssize_t len;
+
+       len = min(count, sizeof(buf) - 1);
+       if (copy_from_user(buf, user_buf, len))
+               return -EFAULT;
+
+       buf[len] = '\0';
+       if (kstrtoul(buf, 0, &val))
+               return -EINVAL;
+
+       if (val < 64 || val > SPECTRAL_ATH10K_MAX_NUM_BINS)
+               return -EINVAL;
+
+       if (!is_power_of_2(val))
+               return -EINVAL;
+
+       mutex_lock(&ar->conf_mutex);
+       ar->spectral.config.fft_size = ilog2(val);
+       ar->spectral.config.fft_size += WMI_SPECTRAL_BIN_SCALE_DEFAULT;
+       mutex_unlock(&ar->conf_mutex);
+
+       return count;
+}
+
+static const struct file_operations fops_spectral_bins = {
+       .read = read_file_spectral_bins,
+       .write = write_file_spectral_bins,
+       .open = simple_open,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
+static struct dentry *create_buf_file_handler(const char *filename,
+                                             struct dentry *parent,
+                                             umode_t mode,
+                                             struct rchan_buf *buf,
+                                             int *is_global)
+{
+       struct dentry *buf_file;
+
+       buf_file = debugfs_create_file(filename, mode, parent, buf,
+                                      &relay_file_operations);
+       *is_global = 1;
+       return buf_file;
+}
+
+static int remove_buf_file_handler(struct dentry *dentry)
+{
+       debugfs_remove(dentry);
+
+       return 0;
+}
+
+static struct rchan_callbacks rfs_spec_scan_cb = {
+       .create_buf_file = create_buf_file_handler,
+       .remove_buf_file = remove_buf_file_handler,
+};
+
+int ath10k_spectral_start(struct ath10k *ar)
+{
+       struct ath10k_vif *arvif;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       list_for_each_entry(arvif, &ar->arvifs, list)
+               arvif->spectral_enabled = 0;
+
+       ar->spectral.mode = SPECTRAL_DISABLED;
+       ar->spectral.config.count = WMI_SPECTRAL_COUNT_DEFAULT;
+       ar->spectral.config.fft_size = WMI_SPECTRAL_FFT_SIZE_DEFAULT;
+
+       return 0;
+}
+
+int ath10k_spectral_vif_stop(struct ath10k_vif *arvif)
+{
+       if (!arvif->spectral_enabled)
+               return 0;
+
+       return ath10k_spectral_scan_config(arvif->ar, SPECTRAL_DISABLED);
+}
+
+int ath10k_spectral_create(struct ath10k *ar)
+{
+       ar->spectral.rfs_chan_spec_scan = relay_open("spectral_scan",
+                                                    ar->debug.debugfs_phy,
+                                                    1024, 256,
+                                                    &rfs_spec_scan_cb, NULL);
+       debugfs_create_file("spectral_scan_ctl",
+                           S_IRUSR | S_IWUSR,
+                           ar->debug.debugfs_phy, ar,
+                           &fops_spec_scan_ctl);
+       debugfs_create_file("spectral_count",
+                           S_IRUSR | S_IWUSR,
+                           ar->debug.debugfs_phy, ar,
+                           &fops_spectral_count);
+       debugfs_create_file("spectral_bins",
+                           S_IRUSR | S_IWUSR,
+                           ar->debug.debugfs_phy, ar,
+                           &fops_spectral_bins);
+
+       return 0;
+}
+
+void ath10k_spectral_destroy(struct ath10k *ar)
+{
+       if (ar->spectral.rfs_chan_spec_scan) {
+               relay_close(ar->spectral.rfs_chan_spec_scan);
+               ar->spectral.rfs_chan_spec_scan = NULL;
+       }
+}
diff --git a/drivers/net/wireless/ath/ath10k/spectral.h b/drivers/net/wireless/ath/ath10k/spectral.h
new file mode 100644 (file)
index 0000000..ddc57c5
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2013 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef SPECTRAL_H
+#define SPECTRAL_H
+
+#include "../spectral_common.h"
+
+/**
+ * struct ath10k_spec_scan - parameters for Atheros spectral scan
+ *
+ * @count: number of scan results requested for manual mode
+ * @fft_size: number of bins to be requested = 2^(fft_size - bin_scale)
+ */
+struct ath10k_spec_scan {
+       u8 count;
+       u8 fft_size;
+};
+
+/* enum ath10k_spectral_mode:
+ *
+ * @SPECTRAL_DISABLED: spectral mode is disabled
+ * @SPECTRAL_BACKGROUND: hardware sends samples when it is not busy with
+ *     something else.
+ * @SPECTRAL_MANUAL: spectral scan is enabled, triggering for samples
+ *     is performed manually.
+ */
+enum ath10k_spectral_mode {
+       SPECTRAL_DISABLED = 0,
+       SPECTRAL_BACKGROUND,
+       SPECTRAL_MANUAL,
+};
+
+#ifdef CONFIG_ATH10K_DEBUGFS
+
+int ath10k_spectral_process_fft(struct ath10k *ar,
+                               struct wmi_single_phyerr_rx_event *event,
+                               struct phyerr_fft_report *fftr,
+                               size_t bin_len, u64 tsf);
+int ath10k_spectral_start(struct ath10k *ar);
+int ath10k_spectral_vif_stop(struct ath10k_vif *arvif);
+int ath10k_spectral_create(struct ath10k *ar);
+void ath10k_spectral_destroy(struct ath10k *ar);
+
+#else
+
+static inline int
+ath10k_spectral_process_fft(struct ath10k *ar,
+                           struct wmi_single_phyerr_rx_event *event,
+                           struct phyerr_fft_report *fftr,
+                           size_t bin_len, u64 tsf)
+{
+       return 0;
+}
+
+static inline int ath10k_spectral_start(struct ath10k *ar)
+{
+       return 0;
+}
+
+static inline int ath10k_spectral_vif_stop(struct ath10k_vif *arvif)
+{
+       return 0;
+}
+
+static inline int ath10k_spectral_create(struct ath10k *ar)
+{
+       return 0;
+}
+
+static inline void ath10k_spectral_destroy(struct ath10k *ar)
+{
+}
+
+#endif /* CONFIG_ATH10K_DEBUGFS */
+
+#endif /* SPECTRAL_H */
index f4fa22d1d5917f358ba408becb33e39e9954ef42..2eeec8a63d5c89732be29291df51dc5edc63e526 100644 (file)
@@ -32,14 +32,14 @@ static void ath10k_report_offchan_tx(struct ath10k *ar, struct sk_buff *skb)
         * offchan_tx_skb. */
        spin_lock_bh(&ar->data_lock);
        if (ar->offchan_tx_skb != skb) {
-               ath10k_warn("completed old offchannel frame\n");
+               ath10k_warn(ar, "completed old offchannel frame\n");
                goto out;
        }
 
        complete(&ar->offchan_tx_completed);
        ar->offchan_tx_skb = NULL; /* just for sanity */
 
-       ath10k_dbg(ATH10K_DBG_HTT, "completed offchannel skb %p\n", skb);
+       ath10k_dbg(ar, ATH10K_DBG_HTT, "completed offchannel skb %p\n", skb);
 out:
        spin_unlock_bh(&ar->data_lock);
 }
@@ -47,18 +47,19 @@ out:
 void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
                          const struct htt_tx_done *tx_done)
 {
-       struct device *dev = htt->ar->dev;
+       struct ath10k *ar = htt->ar;
+       struct device *dev = ar->dev;
        struct ieee80211_tx_info *info;
        struct ath10k_skb_cb *skb_cb;
        struct sk_buff *msdu;
 
        lockdep_assert_held(&htt->tx_lock);
 
-       ath10k_dbg(ATH10K_DBG_HTT, "htt tx completion msdu_id %u discard %d no_ack %d\n",
+       ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx completion msdu_id %u discard %d no_ack %d\n",
                   tx_done->msdu_id, !!tx_done->discard, !!tx_done->no_ack);
 
        if (tx_done->msdu_id >= htt->max_num_pending_tx) {
-               ath10k_warn("warning: msdu_id %d too big, ignoring\n",
+               ath10k_warn(ar, "warning: msdu_id %d too big, ignoring\n",
                            tx_done->msdu_id);
                return;
        }
@@ -182,7 +183,7 @@ void ath10k_peer_map_event(struct ath10k_htt *htt,
                wake_up(&ar->peer_mapping_wq);
        }
 
-       ath10k_dbg(ATH10K_DBG_HTT, "htt peer map vdev %d peer %pM id %d\n",
+       ath10k_dbg(ar, ATH10K_DBG_HTT, "htt peer map vdev %d peer %pM id %d\n",
                   ev->vdev_id, ev->addr, ev->peer_id);
 
        set_bit(ev->peer_id, peer->peer_ids);
@@ -199,12 +200,12 @@ void ath10k_peer_unmap_event(struct ath10k_htt *htt,
        spin_lock_bh(&ar->data_lock);
        peer = ath10k_peer_find_by_id(ar, ev->peer_id);
        if (!peer) {
-               ath10k_warn("peer-unmap-event: unknown peer id %d\n",
+               ath10k_warn(ar, "peer-unmap-event: unknown peer id %d\n",
                            ev->peer_id);
                goto exit;
        }
 
-       ath10k_dbg(ATH10K_DBG_HTT, "htt peer unmap vdev %d peer %pM id %d\n",
+       ath10k_dbg(ar, ATH10K_DBG_HTT, "htt peer unmap vdev %d peer %pM id %d\n",
                   peer->vdev_id, peer->addr, ev->peer_id);
 
        clear_bit(ev->peer_id, peer->peer_ids);
index c2c87c916b5a579f8c6fb4ee2afc45050736e1a0..e500a3cc905e9cfafbb0642896b673d35b187016 100644 (file)
@@ -487,6 +487,127 @@ static struct wmi_pdev_param_map wmi_10x_pdev_param_map = {
        .burst_enable = WMI_10X_PDEV_PARAM_BURST_ENABLE,
 };
 
+/* firmware 10.2 specific mappings */
+static struct wmi_cmd_map wmi_10_2_cmd_map = {
+       .init_cmdid = WMI_10_2_INIT_CMDID,
+       .start_scan_cmdid = WMI_10_2_START_SCAN_CMDID,
+       .stop_scan_cmdid = WMI_10_2_STOP_SCAN_CMDID,
+       .scan_chan_list_cmdid = WMI_10_2_SCAN_CHAN_LIST_CMDID,
+       .scan_sch_prio_tbl_cmdid = WMI_CMD_UNSUPPORTED,
+       .pdev_set_regdomain_cmdid = WMI_10_2_PDEV_SET_REGDOMAIN_CMDID,
+       .pdev_set_channel_cmdid = WMI_10_2_PDEV_SET_CHANNEL_CMDID,
+       .pdev_set_param_cmdid = WMI_10_2_PDEV_SET_PARAM_CMDID,
+       .pdev_pktlog_enable_cmdid = WMI_10_2_PDEV_PKTLOG_ENABLE_CMDID,
+       .pdev_pktlog_disable_cmdid = WMI_10_2_PDEV_PKTLOG_DISABLE_CMDID,
+       .pdev_set_wmm_params_cmdid = WMI_10_2_PDEV_SET_WMM_PARAMS_CMDID,
+       .pdev_set_ht_cap_ie_cmdid = WMI_10_2_PDEV_SET_HT_CAP_IE_CMDID,
+       .pdev_set_vht_cap_ie_cmdid = WMI_10_2_PDEV_SET_VHT_CAP_IE_CMDID,
+       .pdev_set_quiet_mode_cmdid = WMI_10_2_PDEV_SET_QUIET_MODE_CMDID,
+       .pdev_green_ap_ps_enable_cmdid = WMI_10_2_PDEV_GREEN_AP_PS_ENABLE_CMDID,
+       .pdev_get_tpc_config_cmdid = WMI_10_2_PDEV_GET_TPC_CONFIG_CMDID,
+       .pdev_set_base_macaddr_cmdid = WMI_10_2_PDEV_SET_BASE_MACADDR_CMDID,
+       .vdev_create_cmdid = WMI_10_2_VDEV_CREATE_CMDID,
+       .vdev_delete_cmdid = WMI_10_2_VDEV_DELETE_CMDID,
+       .vdev_start_request_cmdid = WMI_10_2_VDEV_START_REQUEST_CMDID,
+       .vdev_restart_request_cmdid = WMI_10_2_VDEV_RESTART_REQUEST_CMDID,
+       .vdev_up_cmdid = WMI_10_2_VDEV_UP_CMDID,
+       .vdev_stop_cmdid = WMI_10_2_VDEV_STOP_CMDID,
+       .vdev_down_cmdid = WMI_10_2_VDEV_DOWN_CMDID,
+       .vdev_set_param_cmdid = WMI_10_2_VDEV_SET_PARAM_CMDID,
+       .vdev_install_key_cmdid = WMI_10_2_VDEV_INSTALL_KEY_CMDID,
+       .peer_create_cmdid = WMI_10_2_PEER_CREATE_CMDID,
+       .peer_delete_cmdid = WMI_10_2_PEER_DELETE_CMDID,
+       .peer_flush_tids_cmdid = WMI_10_2_PEER_FLUSH_TIDS_CMDID,
+       .peer_set_param_cmdid = WMI_10_2_PEER_SET_PARAM_CMDID,
+       .peer_assoc_cmdid = WMI_10_2_PEER_ASSOC_CMDID,
+       .peer_add_wds_entry_cmdid = WMI_10_2_PEER_ADD_WDS_ENTRY_CMDID,
+       .peer_remove_wds_entry_cmdid = WMI_10_2_PEER_REMOVE_WDS_ENTRY_CMDID,
+       .peer_mcast_group_cmdid = WMI_10_2_PEER_MCAST_GROUP_CMDID,
+       .bcn_tx_cmdid = WMI_10_2_BCN_TX_CMDID,
+       .pdev_send_bcn_cmdid = WMI_10_2_PDEV_SEND_BCN_CMDID,
+       .bcn_tmpl_cmdid = WMI_CMD_UNSUPPORTED,
+       .bcn_filter_rx_cmdid = WMI_10_2_BCN_FILTER_RX_CMDID,
+       .prb_req_filter_rx_cmdid = WMI_10_2_PRB_REQ_FILTER_RX_CMDID,
+       .mgmt_tx_cmdid = WMI_10_2_MGMT_TX_CMDID,
+       .prb_tmpl_cmdid = WMI_CMD_UNSUPPORTED,
+       .addba_clear_resp_cmdid = WMI_10_2_ADDBA_CLEAR_RESP_CMDID,
+       .addba_send_cmdid = WMI_10_2_ADDBA_SEND_CMDID,
+       .addba_status_cmdid = WMI_10_2_ADDBA_STATUS_CMDID,
+       .delba_send_cmdid = WMI_10_2_DELBA_SEND_CMDID,
+       .addba_set_resp_cmdid = WMI_10_2_ADDBA_SET_RESP_CMDID,
+       .send_singleamsdu_cmdid = WMI_10_2_SEND_SINGLEAMSDU_CMDID,
+       .sta_powersave_mode_cmdid = WMI_10_2_STA_POWERSAVE_MODE_CMDID,
+       .sta_powersave_param_cmdid = WMI_10_2_STA_POWERSAVE_PARAM_CMDID,
+       .sta_mimo_ps_mode_cmdid = WMI_10_2_STA_MIMO_PS_MODE_CMDID,
+       .pdev_dfs_enable_cmdid = WMI_10_2_PDEV_DFS_ENABLE_CMDID,
+       .pdev_dfs_disable_cmdid = WMI_10_2_PDEV_DFS_DISABLE_CMDID,
+       .roam_scan_mode = WMI_10_2_ROAM_SCAN_MODE,
+       .roam_scan_rssi_threshold = WMI_10_2_ROAM_SCAN_RSSI_THRESHOLD,
+       .roam_scan_period = WMI_10_2_ROAM_SCAN_PERIOD,
+       .roam_scan_rssi_change_threshold =
+                               WMI_10_2_ROAM_SCAN_RSSI_CHANGE_THRESHOLD,
+       .roam_ap_profile = WMI_10_2_ROAM_AP_PROFILE,
+       .ofl_scan_add_ap_profile = WMI_10_2_OFL_SCAN_ADD_AP_PROFILE,
+       .ofl_scan_remove_ap_profile = WMI_10_2_OFL_SCAN_REMOVE_AP_PROFILE,
+       .ofl_scan_period = WMI_10_2_OFL_SCAN_PERIOD,
+       .p2p_dev_set_device_info = WMI_10_2_P2P_DEV_SET_DEVICE_INFO,
+       .p2p_dev_set_discoverability = WMI_10_2_P2P_DEV_SET_DISCOVERABILITY,
+       .p2p_go_set_beacon_ie = WMI_10_2_P2P_GO_SET_BEACON_IE,
+       .p2p_go_set_probe_resp_ie = WMI_10_2_P2P_GO_SET_PROBE_RESP_IE,
+       .p2p_set_vendor_ie_data_cmdid = WMI_CMD_UNSUPPORTED,
+       .ap_ps_peer_param_cmdid = WMI_10_2_AP_PS_PEER_PARAM_CMDID,
+       .ap_ps_peer_uapsd_coex_cmdid = WMI_CMD_UNSUPPORTED,
+       .peer_rate_retry_sched_cmdid = WMI_10_2_PEER_RATE_RETRY_SCHED_CMDID,
+       .wlan_profile_trigger_cmdid = WMI_10_2_WLAN_PROFILE_TRIGGER_CMDID,
+       .wlan_profile_set_hist_intvl_cmdid =
+                               WMI_10_2_WLAN_PROFILE_SET_HIST_INTVL_CMDID,
+       .wlan_profile_get_profile_data_cmdid =
+                               WMI_10_2_WLAN_PROFILE_GET_PROFILE_DATA_CMDID,
+       .wlan_profile_enable_profile_id_cmdid =
+                               WMI_10_2_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID,
+       .wlan_profile_list_profile_id_cmdid =
+                               WMI_10_2_WLAN_PROFILE_LIST_PROFILE_ID_CMDID,
+       .pdev_suspend_cmdid = WMI_10_2_PDEV_SUSPEND_CMDID,
+       .pdev_resume_cmdid = WMI_10_2_PDEV_RESUME_CMDID,
+       .add_bcn_filter_cmdid = WMI_10_2_ADD_BCN_FILTER_CMDID,
+       .rmv_bcn_filter_cmdid = WMI_10_2_RMV_BCN_FILTER_CMDID,
+       .wow_add_wake_pattern_cmdid = WMI_10_2_WOW_ADD_WAKE_PATTERN_CMDID,
+       .wow_del_wake_pattern_cmdid = WMI_10_2_WOW_DEL_WAKE_PATTERN_CMDID,
+       .wow_enable_disable_wake_event_cmdid =
+                               WMI_10_2_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID,
+       .wow_enable_cmdid = WMI_10_2_WOW_ENABLE_CMDID,
+       .wow_hostwakeup_from_sleep_cmdid =
+                               WMI_10_2_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID,
+       .rtt_measreq_cmdid = WMI_10_2_RTT_MEASREQ_CMDID,
+       .rtt_tsf_cmdid = WMI_10_2_RTT_TSF_CMDID,
+       .vdev_spectral_scan_configure_cmdid =
+                               WMI_10_2_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID,
+       .vdev_spectral_scan_enable_cmdid =
+                               WMI_10_2_VDEV_SPECTRAL_SCAN_ENABLE_CMDID,
+       .request_stats_cmdid = WMI_10_2_REQUEST_STATS_CMDID,
+       .set_arp_ns_offload_cmdid = WMI_CMD_UNSUPPORTED,
+       .network_list_offload_config_cmdid = WMI_CMD_UNSUPPORTED,
+       .gtk_offload_cmdid = WMI_CMD_UNSUPPORTED,
+       .csa_offload_enable_cmdid = WMI_CMD_UNSUPPORTED,
+       .csa_offload_chanswitch_cmdid = WMI_CMD_UNSUPPORTED,
+       .chatter_set_mode_cmdid = WMI_CMD_UNSUPPORTED,
+       .peer_tid_addba_cmdid = WMI_CMD_UNSUPPORTED,
+       .peer_tid_delba_cmdid = WMI_CMD_UNSUPPORTED,
+       .sta_dtim_ps_method_cmdid = WMI_CMD_UNSUPPORTED,
+       .sta_uapsd_auto_trig_cmdid = WMI_CMD_UNSUPPORTED,
+       .sta_keepalive_cmd = WMI_CMD_UNSUPPORTED,
+       .echo_cmdid = WMI_10_2_ECHO_CMDID,
+       .pdev_utf_cmdid = WMI_10_2_PDEV_UTF_CMDID,
+       .dbglog_cfg_cmdid = WMI_10_2_DBGLOG_CFG_CMDID,
+       .pdev_qvit_cmdid = WMI_10_2_PDEV_QVIT_CMDID,
+       .pdev_ftm_intg_cmdid = WMI_CMD_UNSUPPORTED,
+       .vdev_set_keepalive_cmdid = WMI_CMD_UNSUPPORTED,
+       .vdev_get_keepalive_cmdid = WMI_CMD_UNSUPPORTED,
+       .force_fw_hang_cmdid = WMI_CMD_UNSUPPORTED,
+       .gpio_config_cmdid = WMI_10_2_GPIO_CONFIG_CMDID,
+       .gpio_output_cmdid = WMI_10_2_GPIO_OUTPUT_CMDID,
+};
+
 int ath10k_wmi_wait_for_service_ready(struct ath10k *ar)
 {
        int ret;
@@ -503,18 +624,18 @@ int ath10k_wmi_wait_for_unified_ready(struct ath10k *ar)
        return ret;
 }
 
-static struct sk_buff *ath10k_wmi_alloc_skb(u32 len)
+static struct sk_buff *ath10k_wmi_alloc_skb(struct ath10k *ar, u32 len)
 {
        struct sk_buff *skb;
        u32 round_len = roundup(len, 4);
 
-       skb = ath10k_htc_alloc_skb(WMI_SKB_HEADROOM + round_len);
+       skb = ath10k_htc_alloc_skb(ar, WMI_SKB_HEADROOM + round_len);
        if (!skb)
                return NULL;
 
        skb_reserve(skb, WMI_SKB_HEADROOM);
        if (!IS_ALIGNED((unsigned long)skb->data, 4))
-               ath10k_warn("Unaligned WMI skb\n");
+               ath10k_warn(ar, "Unaligned WMI skb\n");
 
        skb_put(skb, round_len);
        memset(skb->data, 0, round_len);
@@ -612,7 +733,7 @@ static int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb,
        might_sleep();
 
        if (cmd_id == WMI_CMD_UNSUPPORTED) {
-               ath10k_warn("wmi command %d is not supported by firmware\n",
+               ath10k_warn(ar, "wmi command %d is not supported by firmware\n",
                            cmd_id);
                return ret;
        }
@@ -660,7 +781,7 @@ int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb)
 
        len = round_up(len, 4);
 
-       wmi_skb = ath10k_wmi_alloc_skb(len);
+       wmi_skb = ath10k_wmi_alloc_skb(ar, len);
        if (!wmi_skb)
                return -ENOMEM;
 
@@ -674,7 +795,7 @@ int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb)
        memcpy(cmd->hdr.peer_macaddr.addr, ieee80211_get_DA(hdr), ETH_ALEN);
        memcpy(cmd->buf, skb->data, skb->len);
 
-       ath10k_dbg(ATH10K_DBG_WMI, "wmi mgmt tx skb %p len %d ftype %02x stype %02x\n",
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi mgmt tx skb %p len %d ftype %02x stype %02x\n",
                   wmi_skb, wmi_skb->len, fc & IEEE80211_FCTL_FTYPE,
                   fc & IEEE80211_FCTL_STYPE);
 
@@ -690,6 +811,130 @@ int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb)
        return ret;
 }
 
+static void ath10k_wmi_event_scan_started(struct ath10k *ar)
+{
+       lockdep_assert_held(&ar->data_lock);
+
+       switch (ar->scan.state) {
+       case ATH10K_SCAN_IDLE:
+       case ATH10K_SCAN_RUNNING:
+       case ATH10K_SCAN_ABORTING:
+               ath10k_warn(ar, "received scan started event in an invalid scan state: %s (%d)\n",
+                           ath10k_scan_state_str(ar->scan.state),
+                           ar->scan.state);
+               break;
+       case ATH10K_SCAN_STARTING:
+               ar->scan.state = ATH10K_SCAN_RUNNING;
+
+               if (ar->scan.is_roc)
+                       ieee80211_ready_on_channel(ar->hw);
+
+               complete(&ar->scan.started);
+               break;
+       }
+}
+
+static void ath10k_wmi_event_scan_completed(struct ath10k *ar)
+{
+       lockdep_assert_held(&ar->data_lock);
+
+       switch (ar->scan.state) {
+       case ATH10K_SCAN_IDLE:
+       case ATH10K_SCAN_STARTING:
+               /* One suspected reason scan can be completed while starting is
+                * if firmware fails to deliver all scan events to the host,
+                * e.g. when transport pipe is full. This has been observed
+                * with spectral scan phyerr events starving wmi transport
+                * pipe. In such case the "scan completed" event should be (and
+                * is) ignored by the host as it may be just firmware's scan
+                * state machine recovering.
+                */
+               ath10k_warn(ar, "received scan completed event in an invalid scan state: %s (%d)\n",
+                           ath10k_scan_state_str(ar->scan.state),
+                           ar->scan.state);
+               break;
+       case ATH10K_SCAN_RUNNING:
+       case ATH10K_SCAN_ABORTING:
+               __ath10k_scan_finish(ar);
+               break;
+       }
+}
+
+static void ath10k_wmi_event_scan_bss_chan(struct ath10k *ar)
+{
+       lockdep_assert_held(&ar->data_lock);
+
+       switch (ar->scan.state) {
+       case ATH10K_SCAN_IDLE:
+       case ATH10K_SCAN_STARTING:
+               ath10k_warn(ar, "received scan bss chan event in an invalid scan state: %s (%d)\n",
+                           ath10k_scan_state_str(ar->scan.state),
+                           ar->scan.state);
+               break;
+       case ATH10K_SCAN_RUNNING:
+       case ATH10K_SCAN_ABORTING:
+               ar->scan_channel = NULL;
+               break;
+       }
+}
+
+static void ath10k_wmi_event_scan_foreign_chan(struct ath10k *ar, u32 freq)
+{
+       lockdep_assert_held(&ar->data_lock);
+
+       switch (ar->scan.state) {
+       case ATH10K_SCAN_IDLE:
+       case ATH10K_SCAN_STARTING:
+               ath10k_warn(ar, "received scan foreign chan event in an invalid scan state: %s (%d)\n",
+                           ath10k_scan_state_str(ar->scan.state),
+                           ar->scan.state);
+               break;
+       case ATH10K_SCAN_RUNNING:
+       case ATH10K_SCAN_ABORTING:
+               ar->scan_channel = ieee80211_get_channel(ar->hw->wiphy, freq);
+
+               if (ar->scan.is_roc && ar->scan.roc_freq == freq)
+                       complete(&ar->scan.on_channel);
+               break;
+       }
+}
+
+static const char *
+ath10k_wmi_event_scan_type_str(enum wmi_scan_event_type type,
+                              enum wmi_scan_completion_reason reason)
+{
+       switch (type) {
+       case WMI_SCAN_EVENT_STARTED:
+               return "started";
+       case WMI_SCAN_EVENT_COMPLETED:
+               switch (reason) {
+               case WMI_SCAN_REASON_COMPLETED:
+                       return "completed";
+               case WMI_SCAN_REASON_CANCELLED:
+                       return "completed [cancelled]";
+               case WMI_SCAN_REASON_PREEMPTED:
+                       return "completed [preempted]";
+               case WMI_SCAN_REASON_TIMEDOUT:
+                       return "completed [timedout]";
+               case WMI_SCAN_REASON_MAX:
+                       break;
+               }
+               return "completed [unknown]";
+       case WMI_SCAN_EVENT_BSS_CHANNEL:
+               return "bss channel";
+       case WMI_SCAN_EVENT_FOREIGN_CHANNEL:
+               return "foreign channel";
+       case WMI_SCAN_EVENT_DEQUEUED:
+               return "dequeued";
+       case WMI_SCAN_EVENT_PREEMPTED:
+               return "preempted";
+       case WMI_SCAN_EVENT_START_FAILED:
+               return "start failed";
+       default:
+               return "unknown";
+       }
+}
+
 static int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb)
 {
        struct wmi_scan_event *event = (struct wmi_scan_event *)skb->data;
@@ -707,81 +952,32 @@ static int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb)
        scan_id    = __le32_to_cpu(event->scan_id);
        vdev_id    = __le32_to_cpu(event->vdev_id);
 
-       ath10k_dbg(ATH10K_DBG_WMI, "WMI_SCAN_EVENTID\n");
-       ath10k_dbg(ATH10K_DBG_WMI,
-                  "scan event type %d reason %d freq %d req_id %d "
-                  "scan_id %d vdev_id %d\n",
-                  event_type, reason, freq, req_id, scan_id, vdev_id);
-
        spin_lock_bh(&ar->data_lock);
 
+       ath10k_dbg(ar, ATH10K_DBG_WMI,
+                  "scan event %s type %d reason %d freq %d req_id %d scan_id %d vdev_id %d state %s (%d)\n",
+                  ath10k_wmi_event_scan_type_str(event_type, reason),
+                  event_type, reason, freq, req_id, scan_id, vdev_id,
+                  ath10k_scan_state_str(ar->scan.state), ar->scan.state);
+
        switch (event_type) {
        case WMI_SCAN_EVENT_STARTED:
-               ath10k_dbg(ATH10K_DBG_WMI, "SCAN_EVENT_STARTED\n");
-               if (ar->scan.in_progress && ar->scan.is_roc)
-                       ieee80211_ready_on_channel(ar->hw);
-
-               complete(&ar->scan.started);
+               ath10k_wmi_event_scan_started(ar);
                break;
        case WMI_SCAN_EVENT_COMPLETED:
-               ath10k_dbg(ATH10K_DBG_WMI, "SCAN_EVENT_COMPLETED\n");
-               switch (reason) {
-               case WMI_SCAN_REASON_COMPLETED:
-                       ath10k_dbg(ATH10K_DBG_WMI, "SCAN_REASON_COMPLETED\n");
-                       break;
-               case WMI_SCAN_REASON_CANCELLED:
-                       ath10k_dbg(ATH10K_DBG_WMI, "SCAN_REASON_CANCELED\n");
-                       break;
-               case WMI_SCAN_REASON_PREEMPTED:
-                       ath10k_dbg(ATH10K_DBG_WMI, "SCAN_REASON_PREEMPTED\n");
-                       break;
-               case WMI_SCAN_REASON_TIMEDOUT:
-                       ath10k_dbg(ATH10K_DBG_WMI, "SCAN_REASON_TIMEDOUT\n");
-                       break;
-               default:
-                       break;
-               }
-
-               ar->scan_channel = NULL;
-               if (!ar->scan.in_progress) {
-                       ath10k_warn("no scan requested, ignoring\n");
-                       break;
-               }
-
-               if (ar->scan.is_roc) {
-                       ath10k_offchan_tx_purge(ar);
-
-                       if (!ar->scan.aborting)
-                               ieee80211_remain_on_channel_expired(ar->hw);
-               } else {
-                       ieee80211_scan_completed(ar->hw, ar->scan.aborting);
-               }
-
-               del_timer(&ar->scan.timeout);
-               complete_all(&ar->scan.completed);
-               ar->scan.in_progress = false;
+               ath10k_wmi_event_scan_completed(ar);
                break;
        case WMI_SCAN_EVENT_BSS_CHANNEL:
-               ath10k_dbg(ATH10K_DBG_WMI, "SCAN_EVENT_BSS_CHANNEL\n");
-               ar->scan_channel = NULL;
+               ath10k_wmi_event_scan_bss_chan(ar);
                break;
        case WMI_SCAN_EVENT_FOREIGN_CHANNEL:
-               ath10k_dbg(ATH10K_DBG_WMI, "SCAN_EVENT_FOREIGN_CHANNEL\n");
-               ar->scan_channel = ieee80211_get_channel(ar->hw->wiphy, freq);
-               if (ar->scan.in_progress && ar->scan.is_roc &&
-                   ar->scan.roc_freq == freq) {
-                       complete(&ar->scan.on_channel);
-               }
-               break;
-       case WMI_SCAN_EVENT_DEQUEUED:
-               ath10k_dbg(ATH10K_DBG_WMI, "SCAN_EVENT_DEQUEUED\n");
-               break;
-       case WMI_SCAN_EVENT_PREEMPTED:
-               ath10k_dbg(ATH10K_DBG_WMI, "WMI_SCAN_EVENT_PREEMPTED\n");
+               ath10k_wmi_event_scan_foreign_chan(ar, freq);
                break;
        case WMI_SCAN_EVENT_START_FAILED:
-               ath10k_dbg(ATH10K_DBG_WMI, "WMI_SCAN_EVENT_START_FAILED\n");
+               ath10k_warn(ar, "received scan start failure event\n");
                break;
+       case WMI_SCAN_EVENT_DEQUEUED:
+       case WMI_SCAN_EVENT_PREEMPTED:
        default:
                break;
        }
@@ -911,7 +1107,7 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
 
        memset(status, 0, sizeof(*status));
 
-       ath10k_dbg(ATH10K_DBG_MGMT,
+       ath10k_dbg(ar, ATH10K_DBG_MGMT,
                   "event mgmt rx status %08x\n", rx_status);
 
        if (test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags)) {
@@ -947,9 +1143,9 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
 
                if (phy_mode == MODE_11B &&
                    status->band == IEEE80211_BAND_5GHZ)
-                       ath10k_dbg(ATH10K_DBG_MGMT, "wmi mgmt rx 11b (CCK) on 5GHz\n");
+                       ath10k_dbg(ar, ATH10K_DBG_MGMT, "wmi mgmt rx 11b (CCK) on 5GHz\n");
        } else {
-               ath10k_warn("using (unreliable) phy_mode to extract band for mgmt rx\n");
+               ath10k_warn(ar, "using (unreliable) phy_mode to extract band for mgmt rx\n");
                status->band = phy_mode_to_band(phy_mode);
        }
 
@@ -979,12 +1175,12 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
                }
        }
 
-       ath10k_dbg(ATH10K_DBG_MGMT,
+       ath10k_dbg(ar, ATH10K_DBG_MGMT,
                   "event mgmt rx skb %p len %d ftype %02x stype %02x\n",
                   skb, skb->len,
                   fc & IEEE80211_FCTL_FTYPE, fc & IEEE80211_FCTL_STYPE);
 
-       ath10k_dbg(ATH10K_DBG_MGMT,
+       ath10k_dbg(ar, ATH10K_DBG_MGMT,
                   "event mgmt rx freq %d band %d snr %d, rate_idx %d\n",
                   status->freq, status->band, status->signal,
                   status->rate_idx);
@@ -1034,21 +1230,26 @@ static void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb)
        rx_clear_count = __le32_to_cpu(ev->rx_clear_count);
        cycle_count = __le32_to_cpu(ev->cycle_count);
 
-       ath10k_dbg(ATH10K_DBG_WMI,
+       ath10k_dbg(ar, ATH10K_DBG_WMI,
                   "chan info err_code %d freq %d cmd_flags %d noise_floor %d rx_clear_count %d cycle_count %d\n",
                   err_code, freq, cmd_flags, noise_floor, rx_clear_count,
                   cycle_count);
 
        spin_lock_bh(&ar->data_lock);
 
-       if (!ar->scan.in_progress) {
-               ath10k_warn("chan info event without a scan request?\n");
+       switch (ar->scan.state) {
+       case ATH10K_SCAN_IDLE:
+       case ATH10K_SCAN_STARTING:
+               ath10k_warn(ar, "received chan info event without a scan request, ignoring\n");
                goto exit;
+       case ATH10K_SCAN_RUNNING:
+       case ATH10K_SCAN_ABORTING:
+               break;
        }
 
        idx = freq_to_idx(ar, freq);
        if (idx >= ARRAY_SIZE(ar->survey)) {
-               ath10k_warn("chan info: invalid frequency %d (idx %d out of bounds)\n",
+               ath10k_warn(ar, "chan info: invalid frequency %d (idx %d out of bounds)\n",
                            freq, idx);
                goto exit;
        }
@@ -1079,12 +1280,12 @@ exit:
 
 static void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb)
 {
-       ath10k_dbg(ATH10K_DBG_WMI, "WMI_ECHO_EVENTID\n");
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_ECHO_EVENTID\n");
 }
 
 static int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb)
 {
-       ath10k_dbg(ATH10K_DBG_WMI, "wmi event debug mesg len %d\n",
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi event debug mesg len %d\n",
                   skb->len);
 
        trace_ath10k_wmi_dbglog(skb->data, skb->len);
@@ -1097,7 +1298,7 @@ static void ath10k_wmi_event_update_stats(struct ath10k *ar,
 {
        struct wmi_stats_event *ev = (struct wmi_stats_event *)skb->data;
 
-       ath10k_dbg(ATH10K_DBG_WMI, "WMI_UPDATE_STATS_EVENTID\n");
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_UPDATE_STATS_EVENTID\n");
 
        ath10k_debug_read_target_stats(ar, ev);
 }
@@ -1107,7 +1308,7 @@ static void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar,
 {
        struct wmi_vdev_start_response_event *ev;
 
-       ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_START_RESP_EVENTID\n");
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_START_RESP_EVENTID\n");
 
        ev = (struct wmi_vdev_start_response_event *)skb->data;
 
@@ -1120,7 +1321,7 @@ static void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar,
 static void ath10k_wmi_event_vdev_stopped(struct ath10k *ar,
                                          struct sk_buff *skb)
 {
-       ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_STOPPED_EVENTID\n");
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_STOPPED_EVENTID\n");
        complete(&ar->vdev_setup_done);
 }
 
@@ -1132,14 +1333,14 @@ static void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar,
 
        ev = (struct wmi_peer_sta_kickout_event *)skb->data;
 
-       ath10k_dbg(ATH10K_DBG_WMI, "wmi event peer sta kickout %pM\n",
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi event peer sta kickout %pM\n",
                   ev->peer_macaddr.addr);
 
        rcu_read_lock();
 
        sta = ieee80211_find_sta_by_ifaddr(ar->hw, ev->peer_macaddr.addr, NULL);
        if (!sta) {
-               ath10k_warn("Spurious quick kickout for STA %pM\n",
+               ath10k_warn(ar, "Spurious quick kickout for STA %pM\n",
                            ev->peer_macaddr.addr);
                goto exit;
        }
@@ -1216,7 +1417,7 @@ static void ath10k_wmi_update_tim(struct ath10k *ar,
                                    (u8 *)skb_tail_pointer(bcn) - ies);
        if (!ie) {
                if (arvif->vdev_type != WMI_VDEV_TYPE_IBSS)
-                       ath10k_warn("no tim ie found;\n");
+                       ath10k_warn(ar, "no tim ie found;\n");
                return;
        }
 
@@ -1236,12 +1437,12 @@ static void ath10k_wmi_update_tim(struct ath10k *ar,
                        ie_len += expand_size;
                        pvm_len += expand_size;
                } else {
-                       ath10k_warn("tim expansion failed\n");
+                       ath10k_warn(ar, "tim expansion failed\n");
                }
        }
 
        if (pvm_len > sizeof(arvif->u.ap.tim_bitmap)) {
-               ath10k_warn("tim pvm length is too great (%d)\n", pvm_len);
+               ath10k_warn(ar, "tim pvm length is too great (%d)\n", pvm_len);
                return;
        }
 
@@ -1255,7 +1456,7 @@ static void ath10k_wmi_update_tim(struct ath10k *ar,
                        ATH10K_SKB_CB(bcn)->bcn.deliver_cab = true;
        }
 
-       ath10k_dbg(ATH10K_DBG_MGMT, "dtim %d/%d mcast %d pvmlen %d\n",
+       ath10k_dbg(ar, ATH10K_DBG_MGMT, "dtim %d/%d mcast %d pvmlen %d\n",
                   tim->dtim_count, tim->dtim_period,
                   tim->bitmap_ctrl, pvm_len);
 }
@@ -1333,7 +1534,7 @@ static void ath10k_wmi_update_noa(struct ath10k *ar, struct ath10k_vif *arvif,
        if (arvif->vdev_subtype != WMI_VDEV_SUBTYPE_P2P_GO)
                return;
 
-       ath10k_dbg(ATH10K_DBG_MGMT, "noa changed: %d\n", noa->changed);
+       ath10k_dbg(ar, ATH10K_DBG_MGMT, "noa changed: %d\n", noa->changed);
        if (noa->changed & WMI_P2P_NOA_CHANGED_BIT) {
                new_len = ath10k_p2p_calc_noa_ie_len(noa);
                if (!new_len)
@@ -1381,7 +1582,7 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
        ev = (struct wmi_host_swba_event *)skb->data;
        map = __le32_to_cpu(ev->vdev_map);
 
-       ath10k_dbg(ATH10K_DBG_MGMT, "mgmt swba vdev_map 0x%x\n",
+       ath10k_dbg(ar, ATH10K_DBG_MGMT, "mgmt swba vdev_map 0x%x\n",
                   ev->vdev_map);
 
        for (; map; map >>= 1, vdev_id++) {
@@ -1391,13 +1592,13 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
                i++;
 
                if (i >= WMI_MAX_AP_VDEV) {
-                       ath10k_warn("swba has corrupted vdev map\n");
+                       ath10k_warn(ar, "swba has corrupted vdev map\n");
                        break;
                }
 
                bcn_info = &ev->bcn_info[i];
 
-               ath10k_dbg(ATH10K_DBG_MGMT,
+               ath10k_dbg(ar, ATH10K_DBG_MGMT,
                           "mgmt event bcn_info %d tim_len %d mcast %d changed %d num_ps_pending %d bitmap 0x%08x%08x%08x%08x\n",
                           i,
                           __le32_to_cpu(bcn_info->tim_info.tim_len),
@@ -1411,7 +1612,8 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
 
                arvif = ath10k_get_arvif(ar, vdev_id);
                if (arvif == NULL) {
-                       ath10k_warn("no vif for vdev_id %d found\n", vdev_id);
+                       ath10k_warn(ar, "no vif for vdev_id %d found\n",
+                                   vdev_id);
                        continue;
                }
 
@@ -1428,7 +1630,7 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
 
                bcn = ieee80211_beacon_get(ar->hw, arvif->vif);
                if (!bcn) {
-                       ath10k_warn("could not get mac80211 beacon\n");
+                       ath10k_warn(ar, "could not get mac80211 beacon\n");
                        continue;
                }
 
@@ -1440,7 +1642,7 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
 
                if (arvif->beacon) {
                        if (!arvif->beacon_sent)
-                               ath10k_warn("SWBA overrun on vdev %d\n",
+                               ath10k_warn(ar, "SWBA overrun on vdev %d\n",
                                            arvif->vdev_id);
 
                        dma_unmap_single(arvif->ar->dev,
@@ -1456,7 +1658,7 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
                ret = dma_mapping_error(arvif->ar->dev,
                                        ATH10K_SKB_CB(bcn)->paddr);
                if (ret) {
-                       ath10k_warn("failed to map beacon: %d\n", ret);
+                       ath10k_warn(ar, "failed to map beacon: %d\n", ret);
                        dev_kfree_skb_any(bcn);
                        goto skip;
                }
@@ -1473,7 +1675,7 @@ skip:
 static void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar,
                                               struct sk_buff *skb)
 {
-       ath10k_dbg(ATH10K_DBG_WMI, "WMI_TBTTOFFSET_UPDATE_EVENTID\n");
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TBTTOFFSET_UPDATE_EVENTID\n");
 }
 
 static void ath10k_dfs_radar_report(struct ath10k *ar,
@@ -1489,20 +1691,20 @@ static void ath10k_dfs_radar_report(struct ath10k *ar,
        reg0 = __le32_to_cpu(rr->reg0);
        reg1 = __le32_to_cpu(rr->reg1);
 
-       ath10k_dbg(ATH10K_DBG_REGULATORY,
+       ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
                   "wmi phyerr radar report chirp %d max_width %d agc_total_gain %d pulse_delta_diff %d\n",
                   MS(reg0, RADAR_REPORT_REG0_PULSE_IS_CHIRP),
                   MS(reg0, RADAR_REPORT_REG0_PULSE_IS_MAX_WIDTH),
                   MS(reg0, RADAR_REPORT_REG0_AGC_TOTAL_GAIN),
                   MS(reg0, RADAR_REPORT_REG0_PULSE_DELTA_DIFF));
-       ath10k_dbg(ATH10K_DBG_REGULATORY,
+       ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
                   "wmi phyerr radar report pulse_delta_pean %d pulse_sidx %d fft_valid %d agc_mb_gain %d subchan_mask %d\n",
                   MS(reg0, RADAR_REPORT_REG0_PULSE_DELTA_PEAK),
                   MS(reg0, RADAR_REPORT_REG0_PULSE_SIDX),
                   MS(reg1, RADAR_REPORT_REG1_PULSE_SRCH_FFT_VALID),
                   MS(reg1, RADAR_REPORT_REG1_PULSE_AGC_MB_GAIN),
                   MS(reg1, RADAR_REPORT_REG1_PULSE_SUBCHAN_MASK));
-       ath10k_dbg(ATH10K_DBG_REGULATORY,
+       ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
                   "wmi phyerr radar report pulse_tsf_offset 0x%X pulse_dur: %d\n",
                   MS(reg1, RADAR_REPORT_REG1_PULSE_TSF_OFFSET),
                   MS(reg1, RADAR_REPORT_REG1_PULSE_DUR));
@@ -1529,25 +1731,25 @@ static void ath10k_dfs_radar_report(struct ath10k *ar,
        pe.width = width;
        pe.rssi = rssi;
 
-       ath10k_dbg(ATH10K_DBG_REGULATORY,
+       ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
                   "dfs add pulse freq: %d, width: %d, rssi %d, tsf: %llX\n",
                   pe.freq, pe.width, pe.rssi, pe.ts);
 
        ATH10K_DFS_STAT_INC(ar, pulses_detected);
 
        if (!ar->dfs_detector->add_pulse(ar->dfs_detector, &pe)) {
-               ath10k_dbg(ATH10K_DBG_REGULATORY,
+               ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
                           "dfs no pulse pattern detected, yet\n");
                return;
        }
 
-       ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs radar detected\n");
+       ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "dfs radar detected\n");
        ATH10K_DFS_STAT_INC(ar, radar_detected);
 
        /* Control radar events reporting in debugfs file
           dfs_block_radar_events */
        if (ar->dfs_block_radar_events) {
-               ath10k_info("DFS Radar detected, but ignored as requested\n");
+               ath10k_info(ar, "DFS Radar detected, but ignored as requested\n");
                return;
        }
 
@@ -1566,13 +1768,13 @@ static int ath10k_dfs_fft_report(struct ath10k *ar,
        reg1 = __le32_to_cpu(fftr->reg1);
        rssi = event->hdr.rssi_combined;
 
-       ath10k_dbg(ATH10K_DBG_REGULATORY,
+       ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
                   "wmi phyerr fft report total_gain_db %d base_pwr_db %d fft_chn_idx %d peak_sidx %d\n",
                   MS(reg0, SEARCH_FFT_REPORT_REG0_TOTAL_GAIN_DB),
                   MS(reg0, SEARCH_FFT_REPORT_REG0_BASE_PWR_DB),
                   MS(reg0, SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX),
                   MS(reg0, SEARCH_FFT_REPORT_REG0_PEAK_SIDX));
-       ath10k_dbg(ATH10K_DBG_REGULATORY,
+       ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
                   "wmi phyerr fft report rel_pwr_db %d avgpwr_db %d peak_mag %d num_store_bin %d\n",
                   MS(reg1, SEARCH_FFT_REPORT_REG1_RELPWR_DB),
                   MS(reg1, SEARCH_FFT_REPORT_REG1_AVGPWR_DB),
@@ -1584,7 +1786,7 @@ static int ath10k_dfs_fft_report(struct ath10k *ar,
        /* false event detection */
        if (rssi == DFS_RSSI_POSSIBLY_FALSE &&
            peak_mag < 2 * DFS_PEAK_MAG_THOLD_POSSIBLY_FALSE) {
-               ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs false pulse detected\n");
+               ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "dfs false pulse detected\n");
                ATH10K_DFS_STAT_INC(ar, pulses_discarded);
                return -EINVAL;
        }
@@ -1603,7 +1805,7 @@ static void ath10k_wmi_event_dfs(struct ath10k *ar,
        u8 *tlv_buf;
 
        buf_len = __le32_to_cpu(event->hdr.buf_len);
-       ath10k_dbg(ATH10K_DBG_REGULATORY,
+       ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
                   "wmi event dfs err_code %d rssi %d tsfl 0x%X tsf64 0x%llX len %d\n",
                   event->hdr.phy_err_code, event->hdr.rssi_combined,
                   __le32_to_cpu(event->hdr.tsf_timestamp), tsf, buf_len);
@@ -1616,21 +1818,22 @@ static void ath10k_wmi_event_dfs(struct ath10k *ar,
 
        while (i < buf_len) {
                if (i + sizeof(*tlv) > buf_len) {
-                       ath10k_warn("too short buf for tlv header (%d)\n", i);
+                       ath10k_warn(ar, "too short buf for tlv header (%d)\n",
+                                   i);
                        return;
                }
 
                tlv = (struct phyerr_tlv *)&event->bufp[i];
                tlv_len = __le16_to_cpu(tlv->len);
                tlv_buf = &event->bufp[i + sizeof(*tlv)];
-               ath10k_dbg(ATH10K_DBG_REGULATORY,
+               ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
                           "wmi event dfs tlv_len %d tlv_tag 0x%02X tlv_sig 0x%02X\n",
                           tlv_len, tlv->tag, tlv->sig);
 
                switch (tlv->tag) {
                case PHYERR_TLV_TAG_RADAR_PULSE_SUMMARY:
                        if (i + sizeof(*tlv) + sizeof(*rr) > buf_len) {
-                               ath10k_warn("too short radar pulse summary (%d)\n",
+                               ath10k_warn(ar, "too short radar pulse summary (%d)\n",
                                            i);
                                return;
                        }
@@ -1640,7 +1843,8 @@ static void ath10k_wmi_event_dfs(struct ath10k *ar,
                        break;
                case PHYERR_TLV_TAG_SEARCH_FFT_REPORT:
                        if (i + sizeof(*tlv) + sizeof(*fftr) > buf_len) {
-                               ath10k_warn("too short fft report (%d)\n", i);
+                               ath10k_warn(ar, "too short fft report (%d)\n",
+                                           i);
                                return;
                        }
 
@@ -1659,7 +1863,54 @@ static void ath10k_wmi_event_spectral_scan(struct ath10k *ar,
                                struct wmi_single_phyerr_rx_event *event,
                                u64 tsf)
 {
-       ath10k_dbg(ATH10K_DBG_WMI, "wmi event spectral scan\n");
+       int buf_len, tlv_len, res, i = 0;
+       struct phyerr_tlv *tlv;
+       u8 *tlv_buf;
+       struct phyerr_fft_report *fftr;
+       size_t fftr_len;
+
+       buf_len = __le32_to_cpu(event->hdr.buf_len);
+
+       while (i < buf_len) {
+               if (i + sizeof(*tlv) > buf_len) {
+                       ath10k_warn(ar, "failed to parse phyerr tlv header at byte %d\n",
+                                   i);
+                       return;
+               }
+
+               tlv = (struct phyerr_tlv *)&event->bufp[i];
+               tlv_len = __le16_to_cpu(tlv->len);
+               tlv_buf = &event->bufp[i + sizeof(*tlv)];
+
+               if (i + sizeof(*tlv) + tlv_len > buf_len) {
+                       ath10k_warn(ar, "failed to parse phyerr tlv payload at byte %d\n",
+                                   i);
+                       return;
+               }
+
+               switch (tlv->tag) {
+               case PHYERR_TLV_TAG_SEARCH_FFT_REPORT:
+                       if (sizeof(*fftr) > tlv_len) {
+                               ath10k_warn(ar, "failed to parse fft report at byte %d\n",
+                                           i);
+                               return;
+                       }
+
+                       fftr_len = tlv_len - sizeof(*fftr);
+                       fftr = (struct phyerr_fft_report *)tlv_buf;
+                       res = ath10k_spectral_process_fft(ar, event,
+                                                         fftr, fftr_len,
+                                                         tsf);
+                       if (res < 0) {
+                               ath10k_warn(ar, "failed to process fft report: %d\n",
+                                           res);
+                               return;
+                       }
+                       break;
+               }
+
+               i += sizeof(*tlv) + tlv_len;
+       }
 }
 
 static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb)
@@ -1674,7 +1925,7 @@ static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb)
 
        /* Check if combined event available */
        if (left_len < sizeof(*comb_event)) {
-               ath10k_warn("wmi phyerr combined event wrong len\n");
+               ath10k_warn(ar, "wmi phyerr combined event wrong len\n");
                return;
        }
 
@@ -1688,7 +1939,7 @@ static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb)
        tsf <<= 32;
        tsf |= __le32_to_cpu(comb_event->hdr.tsf_l32);
 
-       ath10k_dbg(ATH10K_DBG_WMI,
+       ath10k_dbg(ar, ATH10K_DBG_WMI,
                   "wmi event phyerr count %d tsf64 0x%llX\n",
                   count, tsf);
 
@@ -1696,7 +1947,8 @@ static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb)
        for (i = 0; i < count; i++) {
                /* Check if we can read event header */
                if (left_len < sizeof(*event)) {
-                       ath10k_warn("single event (%d) wrong head len\n", i);
+                       ath10k_warn(ar, "single event (%d) wrong head len\n",
+                                   i);
                        return;
                }
 
@@ -1706,7 +1958,7 @@ static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb)
                phy_err_code = event->hdr.phy_err_code;
 
                if (left_len < buf_len) {
-                       ath10k_warn("single event (%d) wrong buf len\n", i);
+                       ath10k_warn(ar, "single event (%d) wrong buf len\n", i);
                        return;
                }
 
@@ -1733,13 +1985,13 @@ static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb)
 
 static void ath10k_wmi_event_roam(struct ath10k *ar, struct sk_buff *skb)
 {
-       ath10k_dbg(ATH10K_DBG_WMI, "WMI_ROAM_EVENTID\n");
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_ROAM_EVENTID\n");
 }
 
 static void ath10k_wmi_event_profile_match(struct ath10k *ar,
                                    struct sk_buff *skb)
 {
-       ath10k_dbg(ATH10K_DBG_WMI, "WMI_PROFILE_MATCH\n");
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PROFILE_MATCH\n");
 }
 
 static void ath10k_wmi_event_debug_print(struct ath10k *ar,
@@ -1764,7 +2016,7 @@ static void ath10k_wmi_event_debug_print(struct ath10k *ar,
        }
 
        if (i == sizeof(buf) - 1)
-               ath10k_warn("wmi debug print truncated: %d\n", skb->len);
+               ath10k_warn(ar, "wmi debug print truncated: %d\n", skb->len);
 
        /* for some reason the debug prints end with \n, remove that */
        if (skb->data[i - 1] == '\n')
@@ -1773,108 +2025,108 @@ static void ath10k_wmi_event_debug_print(struct ath10k *ar,
        /* the last byte is always reserved for the null character */
        buf[i] = '\0';
 
-       ath10k_dbg(ATH10K_DBG_WMI, "wmi event debug print '%s'\n", buf);
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi event debug print '%s'\n", buf);
 }
 
 static void ath10k_wmi_event_pdev_qvit(struct ath10k *ar, struct sk_buff *skb)
 {
-       ath10k_dbg(ATH10K_DBG_WMI, "WMI_PDEV_QVIT_EVENTID\n");
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_QVIT_EVENTID\n");
 }
 
 static void ath10k_wmi_event_wlan_profile_data(struct ath10k *ar,
                                               struct sk_buff *skb)
 {
-       ath10k_dbg(ATH10K_DBG_WMI, "WMI_WLAN_PROFILE_DATA_EVENTID\n");
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_WLAN_PROFILE_DATA_EVENTID\n");
 }
 
 static void ath10k_wmi_event_rtt_measurement_report(struct ath10k *ar,
                                             struct sk_buff *skb)
 {
-       ath10k_dbg(ATH10K_DBG_WMI, "WMI_RTT_MEASUREMENT_REPORT_EVENTID\n");
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_RTT_MEASUREMENT_REPORT_EVENTID\n");
 }
 
 static void ath10k_wmi_event_tsf_measurement_report(struct ath10k *ar,
                                             struct sk_buff *skb)
 {
-       ath10k_dbg(ATH10K_DBG_WMI, "WMI_TSF_MEASUREMENT_REPORT_EVENTID\n");
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TSF_MEASUREMENT_REPORT_EVENTID\n");
 }
 
 static void ath10k_wmi_event_rtt_error_report(struct ath10k *ar,
                                              struct sk_buff *skb)
 {
-       ath10k_dbg(ATH10K_DBG_WMI, "WMI_RTT_ERROR_REPORT_EVENTID\n");
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_RTT_ERROR_REPORT_EVENTID\n");
 }
 
 static void ath10k_wmi_event_wow_wakeup_host(struct ath10k *ar,
                                             struct sk_buff *skb)
 {
-       ath10k_dbg(ATH10K_DBG_WMI, "WMI_WOW_WAKEUP_HOST_EVENTID\n");
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_WOW_WAKEUP_HOST_EVENTID\n");
 }
 
 static void ath10k_wmi_event_dcs_interference(struct ath10k *ar,
                                              struct sk_buff *skb)
 {
-       ath10k_dbg(ATH10K_DBG_WMI, "WMI_DCS_INTERFERENCE_EVENTID\n");
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_DCS_INTERFERENCE_EVENTID\n");
 }
 
 static void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar,
                                             struct sk_buff *skb)
 {
-       ath10k_dbg(ATH10K_DBG_WMI, "WMI_PDEV_TPC_CONFIG_EVENTID\n");
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_TPC_CONFIG_EVENTID\n");
 }
 
 static void ath10k_wmi_event_pdev_ftm_intg(struct ath10k *ar,
                                           struct sk_buff *skb)
 {
-       ath10k_dbg(ATH10K_DBG_WMI, "WMI_PDEV_FTM_INTG_EVENTID\n");
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_FTM_INTG_EVENTID\n");
 }
 
 static void ath10k_wmi_event_gtk_offload_status(struct ath10k *ar,
                                         struct sk_buff *skb)
 {
-       ath10k_dbg(ATH10K_DBG_WMI, "WMI_GTK_OFFLOAD_STATUS_EVENTID\n");
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_GTK_OFFLOAD_STATUS_EVENTID\n");
 }
 
 static void ath10k_wmi_event_gtk_rekey_fail(struct ath10k *ar,
                                            struct sk_buff *skb)
 {
-       ath10k_dbg(ATH10K_DBG_WMI, "WMI_GTK_REKEY_FAIL_EVENTID\n");
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_GTK_REKEY_FAIL_EVENTID\n");
 }
 
 static void ath10k_wmi_event_delba_complete(struct ath10k *ar,
                                            struct sk_buff *skb)
 {
-       ath10k_dbg(ATH10K_DBG_WMI, "WMI_TX_DELBA_COMPLETE_EVENTID\n");
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TX_DELBA_COMPLETE_EVENTID\n");
 }
 
 static void ath10k_wmi_event_addba_complete(struct ath10k *ar,
                                            struct sk_buff *skb)
 {
-       ath10k_dbg(ATH10K_DBG_WMI, "WMI_TX_ADDBA_COMPLETE_EVENTID\n");
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TX_ADDBA_COMPLETE_EVENTID\n");
 }
 
 static void ath10k_wmi_event_vdev_install_key_complete(struct ath10k *ar,
                                                struct sk_buff *skb)
 {
-       ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID\n");
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID\n");
 }
 
 static void ath10k_wmi_event_inst_rssi_stats(struct ath10k *ar,
                                             struct sk_buff *skb)
 {
-       ath10k_dbg(ATH10K_DBG_WMI, "WMI_INST_RSSI_STATS_EVENTID\n");
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_INST_RSSI_STATS_EVENTID\n");
 }
 
 static void ath10k_wmi_event_vdev_standby_req(struct ath10k *ar,
                                              struct sk_buff *skb)
 {
-       ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_STANDBY_REQ_EVENTID\n");
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_STANDBY_REQ_EVENTID\n");
 }
 
 static void ath10k_wmi_event_vdev_resume_req(struct ath10k *ar,
                                             struct sk_buff *skb)
 {
-       ath10k_dbg(ATH10K_DBG_WMI, "WMI_VDEV_RESUME_REQ_EVENTID\n");
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_RESUME_REQ_EVENTID\n");
 }
 
 static int ath10k_wmi_alloc_host_mem(struct ath10k *ar, u32 req_id,
@@ -1894,7 +2146,7 @@ static int ath10k_wmi_alloc_host_mem(struct ath10k *ar, u32 req_id,
                                                           &paddr,
                                                           GFP_ATOMIC);
        if (!ar->wmi.mem_chunks[idx].vaddr) {
-               ath10k_warn("failed to allocate memory chunk\n");
+               ath10k_warn(ar, "failed to allocate memory chunk\n");
                return -ENOMEM;
        }
 
@@ -1912,9 +2164,10 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar,
                                              struct sk_buff *skb)
 {
        struct wmi_service_ready_event *ev = (void *)skb->data;
+       DECLARE_BITMAP(svc_bmap, WMI_SERVICE_BM_SIZE) = {};
 
        if (skb->len < sizeof(*ev)) {
-               ath10k_warn("Service ready event was %d B but expected %zu B. Wrong firmware version?\n",
+               ath10k_warn(ar, "Service ready event was %d B but expected %zu B. Wrong firmware version?\n",
                            skb->len, sizeof(*ev));
                return;
        }
@@ -1937,7 +2190,7 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar,
                set_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX, ar->fw_features);
 
        if (ar->num_rf_chains > WMI_MAX_SPATIAL_STREAM) {
-               ath10k_warn("hardware advertises support for more spatial streams than it should (%d > %d)\n",
+               ath10k_warn(ar, "hardware advertises support for more spatial streams than it should (%d > %d)\n",
                            ar->num_rf_chains, WMI_MAX_SPATIAL_STREAM);
                ar->num_rf_chains = WMI_MAX_SPATIAL_STREAM;
        }
@@ -1945,8 +2198,10 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar,
        ar->ath_common.regulatory.current_rd =
                __le32_to_cpu(ev->hal_reg_capabilities.eeprom_rd);
 
-       ath10k_debug_read_service_map(ar, ev->wmi_service_bitmap,
-                                     sizeof(ev->wmi_service_bitmap));
+       wmi_main_svc_map(ev->wmi_service_bitmap, svc_bmap);
+       ath10k_debug_read_service_map(ar, svc_bmap, sizeof(svc_bmap));
+       ath10k_dbg_dump(ar, ATH10K_DBG_WMI, NULL, "wmi svc: ",
+                       ev->wmi_service_bitmap, sizeof(ev->wmi_service_bitmap));
 
        if (strlen(ar->hw->wiphy->fw_version) == 0) {
                snprintf(ar->hw->wiphy->fw_version,
@@ -1960,11 +2215,11 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar,
 
        /* FIXME: it probably should be better to support this */
        if (__le32_to_cpu(ev->num_mem_reqs) > 0) {
-               ath10k_warn("target requested %d memory chunks; ignoring\n",
+               ath10k_warn(ar, "target requested %d memory chunks; ignoring\n",
                            __le32_to_cpu(ev->num_mem_reqs));
        }
 
-       ath10k_dbg(ATH10K_DBG_WMI,
+       ath10k_dbg(ar, ATH10K_DBG_WMI,
                   "wmi event service ready sw_ver 0x%08x sw_ver1 0x%08x abi_ver %u phy_cap 0x%08x ht_cap 0x%08x vht_cap 0x%08x vht_supp_msc 0x%08x sys_cap_info 0x%08x mem_reqs %u num_rf_chains %u\n",
                   __le32_to_cpu(ev->sw_version),
                   __le32_to_cpu(ev->sw_version_1),
@@ -1986,9 +2241,10 @@ static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar,
        u32 num_units, req_id, unit_size, num_mem_reqs, num_unit_info, i;
        int ret;
        struct wmi_service_ready_event_10x *ev = (void *)skb->data;
+       DECLARE_BITMAP(svc_bmap, WMI_SERVICE_BM_SIZE) = {};
 
        if (skb->len < sizeof(*ev)) {
-               ath10k_warn("Service ready event was %d B but expected %zu B. Wrong firmware version?\n",
+               ath10k_warn(ar, "Service ready event was %d B but expected %zu B. Wrong firmware version?\n",
                            skb->len, sizeof(*ev));
                return;
        }
@@ -2004,7 +2260,7 @@ static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar,
        ar->num_rf_chains = __le32_to_cpu(ev->num_rf_chains);
 
        if (ar->num_rf_chains > WMI_MAX_SPATIAL_STREAM) {
-               ath10k_warn("hardware advertises support for more spatial streams than it should (%d > %d)\n",
+               ath10k_warn(ar, "hardware advertises support for more spatial streams than it should (%d > %d)\n",
                            ar->num_rf_chains, WMI_MAX_SPATIAL_STREAM);
                ar->num_rf_chains = WMI_MAX_SPATIAL_STREAM;
        }
@@ -2012,8 +2268,10 @@ static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar,
        ar->ath_common.regulatory.current_rd =
                __le32_to_cpu(ev->hal_reg_capabilities.eeprom_rd);
 
-       ath10k_debug_read_service_map(ar, ev->wmi_service_bitmap,
-                                     sizeof(ev->wmi_service_bitmap));
+       wmi_10x_svc_map(ev->wmi_service_bitmap, svc_bmap);
+       ath10k_debug_read_service_map(ar, svc_bmap, sizeof(svc_bmap));
+       ath10k_dbg_dump(ar, ATH10K_DBG_WMI, NULL, "wmi svc: ",
+                       ev->wmi_service_bitmap, sizeof(ev->wmi_service_bitmap));
 
        if (strlen(ar->hw->wiphy->fw_version) == 0) {
                snprintf(ar->hw->wiphy->fw_version,
@@ -2026,7 +2284,7 @@ static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar,
        num_mem_reqs = __le32_to_cpu(ev->num_mem_reqs);
 
        if (num_mem_reqs > ATH10K_MAX_MEM_REQS) {
-               ath10k_warn("requested memory chunks number (%d) exceeds the limit\n",
+               ath10k_warn(ar, "requested memory chunks number (%d) exceeds the limit\n",
                            num_mem_reqs);
                return;
        }
@@ -2034,7 +2292,7 @@ static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar,
        if (!num_mem_reqs)
                goto exit;
 
-       ath10k_dbg(ATH10K_DBG_WMI, "firmware has requested %d memory chunks\n",
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "firmware has requested %d memory chunks\n",
                   num_mem_reqs);
 
        for (i = 0; i < num_mem_reqs; ++i) {
@@ -2052,7 +2310,7 @@ static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar,
                else if (num_unit_info & NUM_UNITS_IS_NUM_VDEVS)
                        num_units = TARGET_10X_NUM_VDEVS + 1;
 
-               ath10k_dbg(ATH10K_DBG_WMI,
+               ath10k_dbg(ar, ATH10K_DBG_WMI,
                           "wmi mem_req_id %d num_units %d num_unit_info %d unit size %d actual units %d\n",
                           req_id,
                           __le32_to_cpu(ev->mem_reqs[i].num_units),
@@ -2067,7 +2325,7 @@ static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar,
        }
 
 exit:
-       ath10k_dbg(ATH10K_DBG_WMI,
+       ath10k_dbg(ar, ATH10K_DBG_WMI,
                   "wmi event service ready sw_ver 0x%08x abi_ver %u phy_cap 0x%08x ht_cap 0x%08x vht_cap 0x%08x vht_supp_msc 0x%08x sys_cap_info 0x%08x mem_reqs %u num_rf_chains %u\n",
                   __le32_to_cpu(ev->sw_version),
                   __le32_to_cpu(ev->abi_version),
@@ -2091,7 +2349,7 @@ static int ath10k_wmi_ready_event_rx(struct ath10k *ar, struct sk_buff *skb)
 
        memcpy(ar->mac_addr, ev->mac_addr.addr, ETH_ALEN);
 
-       ath10k_dbg(ATH10K_DBG_WMI,
+       ath10k_dbg(ar, ATH10K_DBG_WMI,
                   "wmi event ready sw_version %u abi_version %u mac_addr %pM status %d skb->len %i ev-sz %zu\n",
                   __le32_to_cpu(ev->sw_version),
                   __le32_to_cpu(ev->abi_version),
@@ -2211,7 +2469,7 @@ static void ath10k_wmi_main_process_rx(struct ath10k *ar, struct sk_buff *skb)
                ath10k_wmi_ready_event_rx(ar, skb);
                break;
        default:
-               ath10k_warn("Unknown eventid: %d\n", id);
+               ath10k_warn(ar, "Unknown eventid: %d\n", id);
                break;
        }
 
@@ -2318,27 +2576,151 @@ static void ath10k_wmi_10x_process_rx(struct ath10k *ar, struct sk_buff *skb)
                ath10k_wmi_ready_event_rx(ar, skb);
                break;
        default:
-               ath10k_warn("Unknown eventid: %d\n", id);
+               ath10k_warn(ar, "Unknown eventid: %d\n", id);
                break;
        }
 
        dev_kfree_skb(skb);
 }
 
+static void ath10k_wmi_10_2_process_rx(struct ath10k *ar, struct sk_buff *skb)
+{
+       struct wmi_cmd_hdr *cmd_hdr;
+       enum wmi_10_2_event_id id;
+
+       cmd_hdr = (struct wmi_cmd_hdr *)skb->data;
+       id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID);
+
+       if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL)
+               return;
+
+       trace_ath10k_wmi_event(id, skb->data, skb->len);
+
+       switch (id) {
+       case WMI_10_2_MGMT_RX_EVENTID:
+               ath10k_wmi_event_mgmt_rx(ar, skb);
+               /* mgmt_rx() owns the skb now! */
+               return;
+       case WMI_10_2_SCAN_EVENTID:
+               ath10k_wmi_event_scan(ar, skb);
+               break;
+       case WMI_10_2_CHAN_INFO_EVENTID:
+               ath10k_wmi_event_chan_info(ar, skb);
+               break;
+       case WMI_10_2_ECHO_EVENTID:
+               ath10k_wmi_event_echo(ar, skb);
+               break;
+       case WMI_10_2_DEBUG_MESG_EVENTID:
+               ath10k_wmi_event_debug_mesg(ar, skb);
+               break;
+       case WMI_10_2_UPDATE_STATS_EVENTID:
+               ath10k_wmi_event_update_stats(ar, skb);
+               break;
+       case WMI_10_2_VDEV_START_RESP_EVENTID:
+               ath10k_wmi_event_vdev_start_resp(ar, skb);
+               break;
+       case WMI_10_2_VDEV_STOPPED_EVENTID:
+               ath10k_wmi_event_vdev_stopped(ar, skb);
+               break;
+       case WMI_10_2_PEER_STA_KICKOUT_EVENTID:
+               ath10k_wmi_event_peer_sta_kickout(ar, skb);
+               break;
+       case WMI_10_2_HOST_SWBA_EVENTID:
+               ath10k_wmi_event_host_swba(ar, skb);
+               break;
+       case WMI_10_2_TBTTOFFSET_UPDATE_EVENTID:
+               ath10k_wmi_event_tbttoffset_update(ar, skb);
+               break;
+       case WMI_10_2_PHYERR_EVENTID:
+               ath10k_wmi_event_phyerr(ar, skb);
+               break;
+       case WMI_10_2_ROAM_EVENTID:
+               ath10k_wmi_event_roam(ar, skb);
+               break;
+       case WMI_10_2_PROFILE_MATCH:
+               ath10k_wmi_event_profile_match(ar, skb);
+               break;
+       case WMI_10_2_DEBUG_PRINT_EVENTID:
+               ath10k_wmi_event_debug_print(ar, skb);
+               break;
+       case WMI_10_2_PDEV_QVIT_EVENTID:
+               ath10k_wmi_event_pdev_qvit(ar, skb);
+               break;
+       case WMI_10_2_WLAN_PROFILE_DATA_EVENTID:
+               ath10k_wmi_event_wlan_profile_data(ar, skb);
+               break;
+       case WMI_10_2_RTT_MEASUREMENT_REPORT_EVENTID:
+               ath10k_wmi_event_rtt_measurement_report(ar, skb);
+               break;
+       case WMI_10_2_TSF_MEASUREMENT_REPORT_EVENTID:
+               ath10k_wmi_event_tsf_measurement_report(ar, skb);
+               break;
+       case WMI_10_2_RTT_ERROR_REPORT_EVENTID:
+               ath10k_wmi_event_rtt_error_report(ar, skb);
+               break;
+       case WMI_10_2_WOW_WAKEUP_HOST_EVENTID:
+               ath10k_wmi_event_wow_wakeup_host(ar, skb);
+               break;
+       case WMI_10_2_DCS_INTERFERENCE_EVENTID:
+               ath10k_wmi_event_dcs_interference(ar, skb);
+               break;
+       case WMI_10_2_PDEV_TPC_CONFIG_EVENTID:
+               ath10k_wmi_event_pdev_tpc_config(ar, skb);
+               break;
+       case WMI_10_2_INST_RSSI_STATS_EVENTID:
+               ath10k_wmi_event_inst_rssi_stats(ar, skb);
+               break;
+       case WMI_10_2_VDEV_STANDBY_REQ_EVENTID:
+               ath10k_wmi_event_vdev_standby_req(ar, skb);
+               break;
+       case WMI_10_2_VDEV_RESUME_REQ_EVENTID:
+               ath10k_wmi_event_vdev_resume_req(ar, skb);
+               break;
+       case WMI_10_2_SERVICE_READY_EVENTID:
+               ath10k_wmi_10x_service_ready_event_rx(ar, skb);
+               break;
+       case WMI_10_2_READY_EVENTID:
+               ath10k_wmi_ready_event_rx(ar, skb);
+               break;
+       case WMI_10_2_RTT_KEEPALIVE_EVENTID:
+       case WMI_10_2_GPIO_INPUT_EVENTID:
+       case WMI_10_2_PEER_RATECODE_LIST_EVENTID:
+       case WMI_10_2_GENERIC_BUFFER_EVENTID:
+       case WMI_10_2_MCAST_BUF_RELEASE_EVENTID:
+       case WMI_10_2_MCAST_LIST_AGEOUT_EVENTID:
+       case WMI_10_2_WDS_PEER_EVENTID:
+               ath10k_dbg(ar, ATH10K_DBG_WMI,
+                          "received event id %d not implemented\n", id);
+               break;
+       default:
+               ath10k_warn(ar, "Unknown eventid: %d\n", id);
+               break;
+       }
+
+       dev_kfree_skb(skb);
+}
 
 static void ath10k_wmi_process_rx(struct ath10k *ar, struct sk_buff *skb)
 {
-       if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
-               ath10k_wmi_10x_process_rx(ar, skb);
-       else
+       if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
+               if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
+                       ath10k_wmi_10_2_process_rx(ar, skb);
+               else
+                       ath10k_wmi_10x_process_rx(ar, skb);
+       } else {
                ath10k_wmi_main_process_rx(ar, skb);
+       }
 }
 
 /* WMI Initialization functions */
 int ath10k_wmi_attach(struct ath10k *ar)
 {
        if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
-               ar->wmi.cmd = &wmi_10x_cmd_map;
+               if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
+                       ar->wmi.cmd = &wmi_10_2_cmd_map;
+               else
+                       ar->wmi.cmd = &wmi_10x_cmd_map;
+
                ar->wmi.vdev_param = &wmi_10x_vdev_param_map;
                ar->wmi.pdev_param = &wmi_10x_pdev_param_map;
        } else {
@@ -2388,7 +2770,7 @@ int ath10k_wmi_connect(struct ath10k *ar)
 
        status = ath10k_htc_connect_service(&ar->htc, &conn_req, &conn_resp);
        if (status) {
-               ath10k_warn("failed to connect to WMI CONTROL service status: %d\n",
+               ath10k_warn(ar, "failed to connect to WMI CONTROL service status: %d\n",
                            status);
                return status;
        }
@@ -2404,7 +2786,7 @@ static int ath10k_wmi_main_pdev_set_regdomain(struct ath10k *ar, u16 rd,
        struct wmi_pdev_set_regdomain_cmd *cmd;
        struct sk_buff *skb;
 
-       skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+       skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
        if (!skb)
                return -ENOMEM;
 
@@ -2415,7 +2797,7 @@ static int ath10k_wmi_main_pdev_set_regdomain(struct ath10k *ar, u16 rd,
        cmd->conformance_test_limit_2G = __cpu_to_le32(ctl2g);
        cmd->conformance_test_limit_5G = __cpu_to_le32(ctl5g);
 
-       ath10k_dbg(ATH10K_DBG_WMI,
+       ath10k_dbg(ar, ATH10K_DBG_WMI,
                   "wmi pdev regdomain rd %x rd2g %x rd5g %x ctl2g %x ctl5g %x\n",
                   rd, rd2g, rd5g, ctl2g, ctl5g);
 
@@ -2431,7 +2813,7 @@ static int ath10k_wmi_10x_pdev_set_regdomain(struct ath10k *ar, u16 rd,
        struct wmi_pdev_set_regdomain_cmd_10x *cmd;
        struct sk_buff *skb;
 
-       skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+       skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
        if (!skb)
                return -ENOMEM;
 
@@ -2443,7 +2825,7 @@ static int ath10k_wmi_10x_pdev_set_regdomain(struct ath10k *ar, u16 rd,
        cmd->conformance_test_limit_5G = __cpu_to_le32(ctl5g);
        cmd->dfs_domain = __cpu_to_le32(dfs_reg);
 
-       ath10k_dbg(ATH10K_DBG_WMI,
+       ath10k_dbg(ar, ATH10K_DBG_WMI,
                   "wmi pdev regdomain rd %x rd2g %x rd5g %x ctl2g %x ctl5g %x dfs_region %x\n",
                   rd, rd2g, rd5g, ctl2g, ctl5g, dfs_reg);
 
@@ -2473,7 +2855,7 @@ int ath10k_wmi_pdev_set_channel(struct ath10k *ar,
        if (arg->passive)
                return -EINVAL;
 
-       skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+       skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
        if (!skb)
                return -ENOMEM;
 
@@ -2491,7 +2873,7 @@ int ath10k_wmi_pdev_set_channel(struct ath10k *ar,
        cmd->chan.reg_classid       = arg->reg_class_id;
        cmd->chan.antenna_max       = arg->max_antenna_gain;
 
-       ath10k_dbg(ATH10K_DBG_WMI,
+       ath10k_dbg(ar, ATH10K_DBG_WMI,
                   "wmi set channel mode %d freq %d\n",
                   arg->mode, arg->freq);
 
@@ -2504,7 +2886,7 @@ int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt)
        struct wmi_pdev_suspend_cmd *cmd;
        struct sk_buff *skb;
 
-       skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+       skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
        if (!skb)
                return -ENOMEM;
 
@@ -2518,7 +2900,7 @@ int ath10k_wmi_pdev_resume_target(struct ath10k *ar)
 {
        struct sk_buff *skb;
 
-       skb = ath10k_wmi_alloc_skb(0);
+       skb = ath10k_wmi_alloc_skb(ar, 0);
        if (skb == NULL)
                return -ENOMEM;
 
@@ -2531,11 +2913,12 @@ int ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value)
        struct sk_buff *skb;
 
        if (id == WMI_PDEV_PARAM_UNSUPPORTED) {
-               ath10k_warn("pdev param %d not supported by firmware\n", id);
+               ath10k_warn(ar, "pdev param %d not supported by firmware\n",
+                           id);
                return -EOPNOTSUPP;
        }
 
-       skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+       skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
        if (!skb)
                return -ENOMEM;
 
@@ -2543,7 +2926,7 @@ int ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value)
        cmd->param_id    = __cpu_to_le32(id);
        cmd->param_value = __cpu_to_le32(value);
 
-       ath10k_dbg(ATH10K_DBG_WMI, "wmi pdev set param %d value %d\n",
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi pdev set param %d value %d\n",
                   id, value);
        return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_set_param_cmdid);
 }
@@ -2610,7 +2993,7 @@ static int ath10k_wmi_main_cmd_init(struct ath10k *ar)
        len = sizeof(*cmd) +
              (sizeof(struct host_memory_chunk) * ar->wmi.num_mem_chunks);
 
-       buf = ath10k_wmi_alloc_skb(len);
+       buf = ath10k_wmi_alloc_skb(ar, len);
        if (!buf)
                return -ENOMEM;
 
@@ -2621,7 +3004,7 @@ static int ath10k_wmi_main_cmd_init(struct ath10k *ar)
                goto out;
        }
 
-       ath10k_dbg(ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n",
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n",
                   ar->wmi.num_mem_chunks);
 
        cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks);
@@ -2634,7 +3017,7 @@ static int ath10k_wmi_main_cmd_init(struct ath10k *ar)
                cmd->host_mem_chunks[i].req_id =
                        __cpu_to_le32(ar->wmi.mem_chunks[i].req_id);
 
-               ath10k_dbg(ATH10K_DBG_WMI,
+               ath10k_dbg(ar, ATH10K_DBG_WMI,
                           "wmi chunk %d len %d requested, addr 0x%llx\n",
                           i,
                           ar->wmi.mem_chunks[i].len,
@@ -2643,7 +3026,7 @@ static int ath10k_wmi_main_cmd_init(struct ath10k *ar)
 out:
        memcpy(&cmd->resource_config, &config, sizeof(config));
 
-       ath10k_dbg(ATH10K_DBG_WMI, "wmi init\n");
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init\n");
        return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid);
 }
 
@@ -2701,7 +3084,7 @@ static int ath10k_wmi_10x_cmd_init(struct ath10k *ar)
        len = sizeof(*cmd) +
              (sizeof(struct host_memory_chunk) * ar->wmi.num_mem_chunks);
 
-       buf = ath10k_wmi_alloc_skb(len);
+       buf = ath10k_wmi_alloc_skb(ar, len);
        if (!buf)
                return -ENOMEM;
 
@@ -2712,7 +3095,7 @@ static int ath10k_wmi_10x_cmd_init(struct ath10k *ar)
                goto out;
        }
 
-       ath10k_dbg(ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n",
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n",
                   ar->wmi.num_mem_chunks);
 
        cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks);
@@ -2725,7 +3108,7 @@ static int ath10k_wmi_10x_cmd_init(struct ath10k *ar)
                cmd->host_mem_chunks[i].req_id =
                        __cpu_to_le32(ar->wmi.mem_chunks[i].req_id);
 
-               ath10k_dbg(ATH10K_DBG_WMI,
+               ath10k_dbg(ar, ATH10K_DBG_WMI,
                           "wmi chunk %d len %d requested, addr 0x%llx\n",
                           i,
                           ar->wmi.mem_chunks[i].len,
@@ -2734,7 +3117,98 @@ static int ath10k_wmi_10x_cmd_init(struct ath10k *ar)
 out:
        memcpy(&cmd->resource_config, &config, sizeof(config));
 
-       ath10k_dbg(ATH10K_DBG_WMI, "wmi init 10x\n");
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init 10x\n");
+       return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid);
+}
+
+static int ath10k_wmi_10_2_cmd_init(struct ath10k *ar)
+{
+       struct wmi_init_cmd_10_2 *cmd;
+       struct sk_buff *buf;
+       struct wmi_resource_config_10x config = {};
+       u32 len, val;
+       int i;
+
+       config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS);
+       config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS);
+       config.num_peer_keys = __cpu_to_le32(TARGET_10X_NUM_PEER_KEYS);
+       config.num_tids = __cpu_to_le32(TARGET_10X_NUM_TIDS);
+       config.ast_skid_limit = __cpu_to_le32(TARGET_10X_AST_SKID_LIMIT);
+       config.tx_chain_mask = __cpu_to_le32(TARGET_10X_TX_CHAIN_MASK);
+       config.rx_chain_mask = __cpu_to_le32(TARGET_10X_RX_CHAIN_MASK);
+       config.rx_timeout_pri_vo = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI);
+       config.rx_timeout_pri_vi = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI);
+       config.rx_timeout_pri_be = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI);
+       config.rx_timeout_pri_bk = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_HI_PRI);
+       config.rx_decap_mode = __cpu_to_le32(TARGET_10X_RX_DECAP_MODE);
+
+       config.scan_max_pending_reqs =
+               __cpu_to_le32(TARGET_10X_SCAN_MAX_PENDING_REQS);
+
+       config.bmiss_offload_max_vdev =
+               __cpu_to_le32(TARGET_10X_BMISS_OFFLOAD_MAX_VDEV);
+
+       config.roam_offload_max_vdev =
+               __cpu_to_le32(TARGET_10X_ROAM_OFFLOAD_MAX_VDEV);
+
+       config.roam_offload_max_ap_profiles =
+               __cpu_to_le32(TARGET_10X_ROAM_OFFLOAD_MAX_AP_PROFILES);
+
+       config.num_mcast_groups = __cpu_to_le32(TARGET_10X_NUM_MCAST_GROUPS);
+       config.num_mcast_table_elems =
+               __cpu_to_le32(TARGET_10X_NUM_MCAST_TABLE_ELEMS);
+
+       config.mcast2ucast_mode = __cpu_to_le32(TARGET_10X_MCAST2UCAST_MODE);
+       config.tx_dbg_log_size = __cpu_to_le32(TARGET_10X_TX_DBG_LOG_SIZE);
+       config.num_wds_entries = __cpu_to_le32(TARGET_10X_NUM_WDS_ENTRIES);
+       config.dma_burst_size = __cpu_to_le32(TARGET_10X_DMA_BURST_SIZE);
+       config.mac_aggr_delim = __cpu_to_le32(TARGET_10X_MAC_AGGR_DELIM);
+
+       val = TARGET_10X_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK;
+       config.rx_skip_defrag_timeout_dup_detection_check = __cpu_to_le32(val);
+
+       config.vow_config = __cpu_to_le32(TARGET_10X_VOW_CONFIG);
+
+       config.num_msdu_desc = __cpu_to_le32(TARGET_10X_NUM_MSDU_DESC);
+       config.max_frag_entries = __cpu_to_le32(TARGET_10X_MAX_FRAG_ENTRIES);
+
+       len = sizeof(*cmd) +
+             (sizeof(struct host_memory_chunk) * ar->wmi.num_mem_chunks);
+
+       buf = ath10k_wmi_alloc_skb(ar, len);
+       if (!buf)
+               return -ENOMEM;
+
+       cmd = (struct wmi_init_cmd_10_2 *)buf->data;
+
+       if (ar->wmi.num_mem_chunks == 0) {
+               cmd->num_host_mem_chunks = 0;
+               goto out;
+       }
+
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n",
+                  ar->wmi.num_mem_chunks);
+
+       cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks);
+
+       for (i = 0; i < ar->wmi.num_mem_chunks; i++) {
+               cmd->host_mem_chunks[i].ptr =
+                       __cpu_to_le32(ar->wmi.mem_chunks[i].paddr);
+               cmd->host_mem_chunks[i].size =
+                       __cpu_to_le32(ar->wmi.mem_chunks[i].len);
+               cmd->host_mem_chunks[i].req_id =
+                       __cpu_to_le32(ar->wmi.mem_chunks[i].req_id);
+
+               ath10k_dbg(ar, ATH10K_DBG_WMI,
+                          "wmi chunk %d len %d requested, addr 0x%llx\n",
+                          i,
+                          ar->wmi.mem_chunks[i].len,
+                          (unsigned long long)ar->wmi.mem_chunks[i].paddr);
+       }
+out:
+       memcpy(&cmd->resource_config.common, &config, sizeof(config));
+
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init 10.2\n");
        return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid);
 }
 
@@ -2742,10 +3216,14 @@ int ath10k_wmi_cmd_init(struct ath10k *ar)
 {
        int ret;
 
-       if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
-               ret = ath10k_wmi_10x_cmd_init(ar);
-       else
+       if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
+               if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
+                       ret = ath10k_wmi_10_2_cmd_init(ar);
+               else
+                       ret = ath10k_wmi_10x_cmd_init(ar);
+       } else {
                ret = ath10k_wmi_main_cmd_init(ar);
+       }
 
        return ret;
 }
@@ -2822,7 +3300,7 @@ int ath10k_wmi_start_scan(struct ath10k *ar,
        if (len < 0)
                return len; /* len contains error code here */
 
-       skb = ath10k_wmi_alloc_skb(len);
+       skb = ath10k_wmi_alloc_skb(ar, len);
        if (!skb)
                return -ENOMEM;
 
@@ -2865,8 +3343,8 @@ int ath10k_wmi_start_scan(struct ath10k *ar,
                channels->num_chan = __cpu_to_le32(arg->n_channels);
 
                for (i = 0; i < arg->n_channels; i++)
-                       channels->channel_list[i] =
-                               __cpu_to_le32(arg->channels[i]);
+                       channels->channel_list[i].freq =
+                               __cpu_to_le16(arg->channels[i]);
 
                off += sizeof(*channels);
                off += sizeof(__le32) * arg->n_channels;
@@ -2918,7 +3396,7 @@ int ath10k_wmi_start_scan(struct ath10k *ar,
                return -EINVAL;
        }
 
-       ath10k_dbg(ATH10K_DBG_WMI, "wmi start scan\n");
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi start scan\n");
        return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->start_scan_cmdid);
 }
 
@@ -2960,7 +3438,7 @@ int ath10k_wmi_stop_scan(struct ath10k *ar, const struct wmi_stop_scan_arg *arg)
        if (arg->req_type == WMI_SCAN_STOP_ONE && arg->u.scan_id > 0xFFF)
                return -EINVAL;
 
-       skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+       skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
        if (!skb)
                return -ENOMEM;
 
@@ -2976,7 +3454,7 @@ int ath10k_wmi_stop_scan(struct ath10k *ar, const struct wmi_stop_scan_arg *arg)
        cmd->scan_id     = __cpu_to_le32(scan_id);
        cmd->scan_req_id = __cpu_to_le32(req_id);
 
-       ath10k_dbg(ATH10K_DBG_WMI,
+       ath10k_dbg(ar, ATH10K_DBG_WMI,
                   "wmi stop scan reqid %d req_type %d vdev/scan_id %d\n",
                   arg->req_id, arg->req_type, arg->u.scan_id);
        return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->stop_scan_cmdid);
@@ -2990,7 +3468,7 @@ int ath10k_wmi_vdev_create(struct ath10k *ar, u32 vdev_id,
        struct wmi_vdev_create_cmd *cmd;
        struct sk_buff *skb;
 
-       skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+       skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
        if (!skb)
                return -ENOMEM;
 
@@ -3000,7 +3478,7 @@ int ath10k_wmi_vdev_create(struct ath10k *ar, u32 vdev_id,
        cmd->vdev_subtype = __cpu_to_le32(subtype);
        memcpy(cmd->vdev_macaddr.addr, macaddr, ETH_ALEN);
 
-       ath10k_dbg(ATH10K_DBG_WMI,
+       ath10k_dbg(ar, ATH10K_DBG_WMI,
                   "WMI vdev create: id %d type %d subtype %d macaddr %pM\n",
                   vdev_id, type, subtype, macaddr);
 
@@ -3012,14 +3490,14 @@ int ath10k_wmi_vdev_delete(struct ath10k *ar, u32 vdev_id)
        struct wmi_vdev_delete_cmd *cmd;
        struct sk_buff *skb;
 
-       skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+       skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
        if (!skb)
                return -ENOMEM;
 
        cmd = (struct wmi_vdev_delete_cmd *)skb->data;
        cmd->vdev_id = __cpu_to_le32(vdev_id);
 
-       ath10k_dbg(ATH10K_DBG_WMI,
+       ath10k_dbg(ar, ATH10K_DBG_WMI,
                   "WMI vdev delete id %d\n", vdev_id);
 
        return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_delete_cmdid);
@@ -3052,7 +3530,7 @@ static int ath10k_wmi_vdev_start_restart(struct ath10k *ar,
        else
                return -EINVAL; /* should not happen, we already check cmd_id */
 
-       skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+       skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
        if (!skb)
                return -ENOMEM;
 
@@ -3090,7 +3568,7 @@ static int ath10k_wmi_vdev_start_restart(struct ath10k *ar,
        cmd->chan.reg_classid = arg->channel.reg_class_id;
        cmd->chan.antenna_max = arg->channel.max_antenna_gain;
 
-       ath10k_dbg(ATH10K_DBG_WMI,
+       ath10k_dbg(ar, ATH10K_DBG_WMI,
                   "wmi vdev %s id 0x%x flags: 0x%0X, freq %d, mode %d, "
                   "ch_flags: 0x%0X, max_power: %d\n", cmdname, arg->vdev_id,
                   flags, arg->channel.freq, arg->channel.mode,
@@ -3120,14 +3598,14 @@ int ath10k_wmi_vdev_stop(struct ath10k *ar, u32 vdev_id)
        struct wmi_vdev_stop_cmd *cmd;
        struct sk_buff *skb;
 
-       skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+       skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
        if (!skb)
                return -ENOMEM;
 
        cmd = (struct wmi_vdev_stop_cmd *)skb->data;
        cmd->vdev_id = __cpu_to_le32(vdev_id);
 
-       ath10k_dbg(ATH10K_DBG_WMI, "wmi vdev stop id 0x%x\n", vdev_id);
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi vdev stop id 0x%x\n", vdev_id);
 
        return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_stop_cmdid);
 }
@@ -3137,7 +3615,7 @@ int ath10k_wmi_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid, const u8 *bssid)
        struct wmi_vdev_up_cmd *cmd;
        struct sk_buff *skb;
 
-       skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+       skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
        if (!skb)
                return -ENOMEM;
 
@@ -3146,7 +3624,7 @@ int ath10k_wmi_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid, const u8 *bssid)
        cmd->vdev_assoc_id = __cpu_to_le32(aid);
        memcpy(&cmd->vdev_bssid.addr, bssid, ETH_ALEN);
 
-       ath10k_dbg(ATH10K_DBG_WMI,
+       ath10k_dbg(ar, ATH10K_DBG_WMI,
                   "wmi mgmt vdev up id 0x%x assoc id %d bssid %pM\n",
                   vdev_id, aid, bssid);
 
@@ -3158,14 +3636,14 @@ int ath10k_wmi_vdev_down(struct ath10k *ar, u32 vdev_id)
        struct wmi_vdev_down_cmd *cmd;
        struct sk_buff *skb;
 
-       skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+       skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
        if (!skb)
                return -ENOMEM;
 
        cmd = (struct wmi_vdev_down_cmd *)skb->data;
        cmd->vdev_id = __cpu_to_le32(vdev_id);
 
-       ath10k_dbg(ATH10K_DBG_WMI,
+       ath10k_dbg(ar, ATH10K_DBG_WMI,
                   "wmi mgmt vdev down id 0x%x\n", vdev_id);
 
        return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_down_cmdid);
@@ -3178,13 +3656,13 @@ int ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id,
        struct sk_buff *skb;
 
        if (param_id == WMI_VDEV_PARAM_UNSUPPORTED) {
-               ath10k_dbg(ATH10K_DBG_WMI,
+               ath10k_dbg(ar, ATH10K_DBG_WMI,
                           "vdev param %d not supported by firmware\n",
                            param_id);
                return -EOPNOTSUPP;
        }
 
-       skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+       skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
        if (!skb)
                return -ENOMEM;
 
@@ -3193,7 +3671,7 @@ int ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id,
        cmd->param_id    = __cpu_to_le32(param_id);
        cmd->param_value = __cpu_to_le32(param_value);
 
-       ath10k_dbg(ATH10K_DBG_WMI,
+       ath10k_dbg(ar, ATH10K_DBG_WMI,
                   "wmi vdev id 0x%x set param %d value %d\n",
                   vdev_id, param_id, param_value);
 
@@ -3211,7 +3689,7 @@ int ath10k_wmi_vdev_install_key(struct ath10k *ar,
        if (arg->key_cipher != WMI_CIPHER_NONE && arg->key_data == NULL)
                return -EINVAL;
 
-       skb = ath10k_wmi_alloc_skb(sizeof(*cmd) + arg->key_len);
+       skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd) + arg->key_len);
        if (!skb)
                return -ENOMEM;
 
@@ -3229,20 +3707,76 @@ int ath10k_wmi_vdev_install_key(struct ath10k *ar,
        if (arg->key_data)
                memcpy(cmd->key_data, arg->key_data, arg->key_len);
 
-       ath10k_dbg(ATH10K_DBG_WMI,
+       ath10k_dbg(ar, ATH10K_DBG_WMI,
                   "wmi vdev install key idx %d cipher %d len %d\n",
                   arg->key_idx, arg->key_cipher, arg->key_len);
        return ath10k_wmi_cmd_send(ar, skb,
                                   ar->wmi.cmd->vdev_install_key_cmdid);
 }
 
+int ath10k_wmi_vdev_spectral_conf(struct ath10k *ar,
+                                 const struct wmi_vdev_spectral_conf_arg *arg)
+{
+       struct wmi_vdev_spectral_conf_cmd *cmd;
+       struct sk_buff *skb;
+       u32 cmdid;
+
+       skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_vdev_spectral_conf_cmd *)skb->data;
+       cmd->vdev_id = __cpu_to_le32(arg->vdev_id);
+       cmd->scan_count = __cpu_to_le32(arg->scan_count);
+       cmd->scan_period = __cpu_to_le32(arg->scan_period);
+       cmd->scan_priority = __cpu_to_le32(arg->scan_priority);
+       cmd->scan_fft_size = __cpu_to_le32(arg->scan_fft_size);
+       cmd->scan_gc_ena = __cpu_to_le32(arg->scan_gc_ena);
+       cmd->scan_restart_ena = __cpu_to_le32(arg->scan_restart_ena);
+       cmd->scan_noise_floor_ref = __cpu_to_le32(arg->scan_noise_floor_ref);
+       cmd->scan_init_delay = __cpu_to_le32(arg->scan_init_delay);
+       cmd->scan_nb_tone_thr = __cpu_to_le32(arg->scan_nb_tone_thr);
+       cmd->scan_str_bin_thr = __cpu_to_le32(arg->scan_str_bin_thr);
+       cmd->scan_wb_rpt_mode = __cpu_to_le32(arg->scan_wb_rpt_mode);
+       cmd->scan_rssi_rpt_mode = __cpu_to_le32(arg->scan_rssi_rpt_mode);
+       cmd->scan_rssi_thr = __cpu_to_le32(arg->scan_rssi_thr);
+       cmd->scan_pwr_format = __cpu_to_le32(arg->scan_pwr_format);
+       cmd->scan_rpt_mode = __cpu_to_le32(arg->scan_rpt_mode);
+       cmd->scan_bin_scale = __cpu_to_le32(arg->scan_bin_scale);
+       cmd->scan_dbm_adj = __cpu_to_le32(arg->scan_dbm_adj);
+       cmd->scan_chn_mask = __cpu_to_le32(arg->scan_chn_mask);
+
+       cmdid = ar->wmi.cmd->vdev_spectral_scan_configure_cmdid;
+       return ath10k_wmi_cmd_send(ar, skb, cmdid);
+}
+
+int ath10k_wmi_vdev_spectral_enable(struct ath10k *ar, u32 vdev_id, u32 trigger,
+                                   u32 enable)
+{
+       struct wmi_vdev_spectral_enable_cmd *cmd;
+       struct sk_buff *skb;
+       u32 cmdid;
+
+       skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_vdev_spectral_enable_cmd *)skb->data;
+       cmd->vdev_id = __cpu_to_le32(vdev_id);
+       cmd->trigger_cmd = __cpu_to_le32(trigger);
+       cmd->enable_cmd = __cpu_to_le32(enable);
+
+       cmdid = ar->wmi.cmd->vdev_spectral_scan_enable_cmdid;
+       return ath10k_wmi_cmd_send(ar, skb, cmdid);
+}
+
 int ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id,
                           const u8 peer_addr[ETH_ALEN])
 {
        struct wmi_peer_create_cmd *cmd;
        struct sk_buff *skb;
 
-       skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+       skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
        if (!skb)
                return -ENOMEM;
 
@@ -3250,7 +3784,7 @@ int ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id,
        cmd->vdev_id = __cpu_to_le32(vdev_id);
        memcpy(cmd->peer_macaddr.addr, peer_addr, ETH_ALEN);
 
-       ath10k_dbg(ATH10K_DBG_WMI,
+       ath10k_dbg(ar, ATH10K_DBG_WMI,
                   "wmi peer create vdev_id %d peer_addr %pM\n",
                   vdev_id, peer_addr);
        return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_create_cmdid);
@@ -3262,7 +3796,7 @@ int ath10k_wmi_peer_delete(struct ath10k *ar, u32 vdev_id,
        struct wmi_peer_delete_cmd *cmd;
        struct sk_buff *skb;
 
-       skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+       skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
        if (!skb)
                return -ENOMEM;
 
@@ -3270,7 +3804,7 @@ int ath10k_wmi_peer_delete(struct ath10k *ar, u32 vdev_id,
        cmd->vdev_id = __cpu_to_le32(vdev_id);
        memcpy(cmd->peer_macaddr.addr, peer_addr, ETH_ALEN);
 
-       ath10k_dbg(ATH10K_DBG_WMI,
+       ath10k_dbg(ar, ATH10K_DBG_WMI,
                   "wmi peer delete vdev_id %d peer_addr %pM\n",
                   vdev_id, peer_addr);
        return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_delete_cmdid);
@@ -3282,7 +3816,7 @@ int ath10k_wmi_peer_flush(struct ath10k *ar, u32 vdev_id,
        struct wmi_peer_flush_tids_cmd *cmd;
        struct sk_buff *skb;
 
-       skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+       skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
        if (!skb)
                return -ENOMEM;
 
@@ -3291,7 +3825,7 @@ int ath10k_wmi_peer_flush(struct ath10k *ar, u32 vdev_id,
        cmd->peer_tid_bitmap = __cpu_to_le32(tid_bitmap);
        memcpy(cmd->peer_macaddr.addr, peer_addr, ETH_ALEN);
 
-       ath10k_dbg(ATH10K_DBG_WMI,
+       ath10k_dbg(ar, ATH10K_DBG_WMI,
                   "wmi peer flush vdev_id %d peer_addr %pM tids %08x\n",
                   vdev_id, peer_addr, tid_bitmap);
        return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_flush_tids_cmdid);
@@ -3304,7 +3838,7 @@ int ath10k_wmi_peer_set_param(struct ath10k *ar, u32 vdev_id,
        struct wmi_peer_set_param_cmd *cmd;
        struct sk_buff *skb;
 
-       skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+       skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
        if (!skb)
                return -ENOMEM;
 
@@ -3314,7 +3848,7 @@ int ath10k_wmi_peer_set_param(struct ath10k *ar, u32 vdev_id,
        cmd->param_value = __cpu_to_le32(param_value);
        memcpy(&cmd->peer_macaddr.addr, peer_addr, ETH_ALEN);
 
-       ath10k_dbg(ATH10K_DBG_WMI,
+       ath10k_dbg(ar, ATH10K_DBG_WMI,
                   "wmi vdev %d peer 0x%pM set param %d value %d\n",
                   vdev_id, peer_addr, param_id, param_value);
 
@@ -3327,7 +3861,7 @@ int ath10k_wmi_set_psmode(struct ath10k *ar, u32 vdev_id,
        struct wmi_sta_powersave_mode_cmd *cmd;
        struct sk_buff *skb;
 
-       skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+       skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
        if (!skb)
                return -ENOMEM;
 
@@ -3335,7 +3869,7 @@ int ath10k_wmi_set_psmode(struct ath10k *ar, u32 vdev_id,
        cmd->vdev_id     = __cpu_to_le32(vdev_id);
        cmd->sta_ps_mode = __cpu_to_le32(psmode);
 
-       ath10k_dbg(ATH10K_DBG_WMI,
+       ath10k_dbg(ar, ATH10K_DBG_WMI,
                   "wmi set powersave id 0x%x mode %d\n",
                   vdev_id, psmode);
 
@@ -3350,7 +3884,7 @@ int ath10k_wmi_set_sta_ps_param(struct ath10k *ar, u32 vdev_id,
        struct wmi_sta_powersave_param_cmd *cmd;
        struct sk_buff *skb;
 
-       skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+       skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
        if (!skb)
                return -ENOMEM;
 
@@ -3359,7 +3893,7 @@ int ath10k_wmi_set_sta_ps_param(struct ath10k *ar, u32 vdev_id,
        cmd->param_id    = __cpu_to_le32(param_id);
        cmd->param_value = __cpu_to_le32(value);
 
-       ath10k_dbg(ATH10K_DBG_WMI,
+       ath10k_dbg(ar, ATH10K_DBG_WMI,
                   "wmi sta ps param vdev_id 0x%x param %d value %d\n",
                   vdev_id, param_id, value);
        return ath10k_wmi_cmd_send(ar, skb,
@@ -3375,7 +3909,7 @@ int ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac,
        if (!mac)
                return -EINVAL;
 
-       skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+       skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
        if (!skb)
                return -ENOMEM;
 
@@ -3385,7 +3919,7 @@ int ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac,
        cmd->param_value = __cpu_to_le32(value);
        memcpy(&cmd->peer_macaddr, mac, ETH_ALEN);
 
-       ath10k_dbg(ATH10K_DBG_WMI,
+       ath10k_dbg(ar, ATH10K_DBG_WMI,
                   "wmi ap ps param vdev_id 0x%X param %d value %d mac_addr %pM\n",
                   vdev_id, param_id, value, mac);
 
@@ -3405,7 +3939,7 @@ int ath10k_wmi_scan_chan_list(struct ath10k *ar,
 
        len = sizeof(*cmd) + arg->n_channels * sizeof(struct wmi_channel);
 
-       skb = ath10k_wmi_alloc_skb(len);
+       skb = ath10k_wmi_alloc_skb(ar, len);
        if (!skb)
                return -EINVAL;
 
@@ -3447,24 +3981,12 @@ int ath10k_wmi_scan_chan_list(struct ath10k *ar,
        return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->scan_chan_list_cmdid);
 }
 
-int ath10k_wmi_peer_assoc(struct ath10k *ar,
-                         const struct wmi_peer_assoc_complete_arg *arg)
+static void
+ath10k_wmi_peer_assoc_fill(struct ath10k *ar, void *buf,
+                          const struct wmi_peer_assoc_complete_arg *arg)
 {
-       struct wmi_peer_assoc_complete_cmd *cmd;
-       struct sk_buff *skb;
+       struct wmi_common_peer_assoc_complete_cmd *cmd = buf;
 
-       if (arg->peer_mpdu_density > 16)
-               return -EINVAL;
-       if (arg->peer_legacy_rates.num_rates > MAX_SUPPORTED_RATES)
-               return -EINVAL;
-       if (arg->peer_ht_rates.num_rates > MAX_SUPPORTED_RATES)
-               return -EINVAL;
-
-       skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
-       if (!skb)
-               return -ENOMEM;
-
-       cmd = (struct wmi_peer_assoc_complete_cmd *)skb->data;
        cmd->vdev_id            = __cpu_to_le32(arg->vdev_id);
        cmd->peer_new_assoc     = __cpu_to_le32(arg->peer_reassoc ? 0 : 1);
        cmd->peer_associd       = __cpu_to_le32(arg->peer_aid);
@@ -3499,8 +4021,80 @@ int ath10k_wmi_peer_assoc(struct ath10k *ar,
                __cpu_to_le32(arg->peer_vht_rates.tx_max_rate);
        cmd->peer_vht_rates.tx_mcs_set =
                __cpu_to_le32(arg->peer_vht_rates.tx_mcs_set);
+}
+
+static void
+ath10k_wmi_peer_assoc_fill_main(struct ath10k *ar, void *buf,
+                               const struct wmi_peer_assoc_complete_arg *arg)
+{
+       struct wmi_main_peer_assoc_complete_cmd *cmd = buf;
+
+       ath10k_wmi_peer_assoc_fill(ar, buf, arg);
+       memset(cmd->peer_ht_info, 0, sizeof(cmd->peer_ht_info));
+}
+
+static void
+ath10k_wmi_peer_assoc_fill_10_1(struct ath10k *ar, void *buf,
+                               const struct wmi_peer_assoc_complete_arg *arg)
+{
+       ath10k_wmi_peer_assoc_fill(ar, buf, arg);
+}
+
+static void
+ath10k_wmi_peer_assoc_fill_10_2(struct ath10k *ar, void *buf,
+                               const struct wmi_peer_assoc_complete_arg *arg)
+{
+       struct wmi_10_2_peer_assoc_complete_cmd *cmd = buf;
+       int max_mcs, max_nss;
+       u32 info0;
+
+       /* TODO: Is using max values okay with firmware? */
+       max_mcs = 0xf;
+       max_nss = 0xf;
+
+       info0 = SM(max_mcs, WMI_PEER_ASSOC_INFO0_MAX_MCS_IDX) |
+               SM(max_nss, WMI_PEER_ASSOC_INFO0_MAX_NSS);
+
+       ath10k_wmi_peer_assoc_fill(ar, buf, arg);
+       cmd->info0 = __cpu_to_le32(info0);
+}
+
+int ath10k_wmi_peer_assoc(struct ath10k *ar,
+                         const struct wmi_peer_assoc_complete_arg *arg)
+{
+       struct sk_buff *skb;
+       int len;
+
+       if (arg->peer_mpdu_density > 16)
+               return -EINVAL;
+       if (arg->peer_legacy_rates.num_rates > MAX_SUPPORTED_RATES)
+               return -EINVAL;
+       if (arg->peer_ht_rates.num_rates > MAX_SUPPORTED_RATES)
+               return -EINVAL;
+
+       if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
+               if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
+                       len = sizeof(struct wmi_10_2_peer_assoc_complete_cmd);
+               else
+                       len = sizeof(struct wmi_10_1_peer_assoc_complete_cmd);
+       } else {
+               len = sizeof(struct wmi_main_peer_assoc_complete_cmd);
+       }
+
+       skb = ath10k_wmi_alloc_skb(ar, len);
+       if (!skb)
+               return -ENOMEM;
+
+       if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
+               if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
+                       ath10k_wmi_peer_assoc_fill_10_1(ar, skb->data, arg);
+               else
+                       ath10k_wmi_peer_assoc_fill_10_2(ar, skb->data, arg);
+       } else {
+               ath10k_wmi_peer_assoc_fill_main(ar, skb->data, arg);
+       }
 
-       ath10k_dbg(ATH10K_DBG_WMI,
+       ath10k_dbg(ar, ATH10K_DBG_WMI,
                   "wmi peer assoc vdev %d addr %pM (%s)\n",
                   arg->vdev_id, arg->addr,
                   arg->peer_reassoc ? "reassociate" : "new");
@@ -3518,7 +4112,7 @@ int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif)
        int ret;
        u16 fc;
 
-       skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+       skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
        if (!skb)
                return -ENOMEM;
 
@@ -3532,6 +4126,7 @@ int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif)
        cmd->msdu_id = 0;
        cmd->frame_control = __cpu_to_le32(fc);
        cmd->flags = 0;
+       cmd->antenna_mask = __cpu_to_le32(WMI_BCN_TX_REF_DEF_ANTENNA);
 
        if (ATH10K_SKB_CB(beacon)->bcn.dtim_zero)
                cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DTIM_ZERO);
@@ -3565,7 +4160,7 @@ int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar,
        struct wmi_pdev_set_wmm_params *cmd;
        struct sk_buff *skb;
 
-       skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+       skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
        if (!skb)
                return -ENOMEM;
 
@@ -3575,7 +4170,7 @@ int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar,
        ath10k_wmi_pdev_set_wmm_param(&cmd->ac_vi, &arg->ac_vi);
        ath10k_wmi_pdev_set_wmm_param(&cmd->ac_vo, &arg->ac_vo);
 
-       ath10k_dbg(ATH10K_DBG_WMI, "wmi pdev set wmm params\n");
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi pdev set wmm params\n");
        return ath10k_wmi_cmd_send(ar, skb,
                                   ar->wmi.cmd->pdev_set_wmm_params_cmdid);
 }
@@ -3585,14 +4180,14 @@ int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id)
        struct wmi_request_stats_cmd *cmd;
        struct sk_buff *skb;
 
-       skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+       skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
        if (!skb)
                return -ENOMEM;
 
        cmd = (struct wmi_request_stats_cmd *)skb->data;
        cmd->stats_id = __cpu_to_le32(stats_id);
 
-       ath10k_dbg(ATH10K_DBG_WMI, "wmi request stats %d\n", (int)stats_id);
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi request stats %d\n", (int)stats_id);
        return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->request_stats_cmdid);
 }
 
@@ -3602,7 +4197,7 @@ int ath10k_wmi_force_fw_hang(struct ath10k *ar,
        struct wmi_force_fw_hang_cmd *cmd;
        struct sk_buff *skb;
 
-       skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+       skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
        if (!skb)
                return -ENOMEM;
 
@@ -3610,7 +4205,7 @@ int ath10k_wmi_force_fw_hang(struct ath10k *ar,
        cmd->type = __cpu_to_le32(type);
        cmd->delay_ms = __cpu_to_le32(delay_ms);
 
-       ath10k_dbg(ATH10K_DBG_WMI, "wmi force fw hang %d delay %d\n",
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi force fw hang %d delay %d\n",
                   type, delay_ms);
        return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->force_fw_hang_cmdid);
 }
@@ -3621,7 +4216,7 @@ int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable)
        struct sk_buff *skb;
        u32 cfg;
 
-       skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+       skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
        if (!skb)
                return -ENOMEM;
 
@@ -3642,7 +4237,7 @@ int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable)
        cmd->config_enable = __cpu_to_le32(cfg);
        cmd->config_valid = __cpu_to_le32(ATH10K_DBGLOG_CFG_LOG_LVL_MASK);
 
-       ath10k_dbg(ATH10K_DBG_WMI,
+       ath10k_dbg(ar, ATH10K_DBG_WMI,
                   "wmi dbglog cfg modules %08x %08x config %08x %08x\n",
                   __le32_to_cpu(cmd->module_enable),
                   __le32_to_cpu(cmd->module_valid),
index e93df2c104136a10f03052908ef45ca38f514e6c..e70836586756355657068533085258eab27e1094 100644 (file)
@@ -73,116 +73,279 @@ struct wmi_cmd_hdr {
 #define HTC_PROTOCOL_VERSION    0x0002
 #define WMI_PROTOCOL_VERSION    0x0002
 
-enum wmi_service_id {
-       WMI_SERVICE_BEACON_OFFLOAD = 0,   /* beacon offload */
-       WMI_SERVICE_SCAN_OFFLOAD,         /* scan offload */
-       WMI_SERVICE_ROAM_OFFLOAD,         /* roam offload */
-       WMI_SERVICE_BCN_MISS_OFFLOAD,     /* beacon miss offload */
-       WMI_SERVICE_STA_PWRSAVE,          /* fake sleep + basic power save */
-       WMI_SERVICE_STA_ADVANCED_PWRSAVE, /* uapsd, pspoll, force sleep */
-       WMI_SERVICE_AP_UAPSD,             /* uapsd on AP */
-       WMI_SERVICE_AP_DFS,               /* DFS on AP */
-       WMI_SERVICE_11AC,                 /* supports 11ac */
-       WMI_SERVICE_BLOCKACK,   /* Supports triggering ADDBA/DELBA from host*/
-       WMI_SERVICE_PHYERR,               /* PHY error */
-       WMI_SERVICE_BCN_FILTER,           /* Beacon filter support */
-       WMI_SERVICE_RTT,                  /* RTT (round trip time) support */
-       WMI_SERVICE_RATECTRL,             /* Rate-control */
-       WMI_SERVICE_WOW,                  /* WOW Support */
-       WMI_SERVICE_RATECTRL_CACHE,       /* Rate-control caching */
-       WMI_SERVICE_IRAM_TIDS,            /* TIDs in IRAM */
-       WMI_SERVICE_ARPNS_OFFLOAD,        /* ARP NS Offload support */
-       WMI_SERVICE_NLO,                  /* Network list offload service */
-       WMI_SERVICE_GTK_OFFLOAD,          /* GTK offload */
-       WMI_SERVICE_SCAN_SCH,             /* Scan Scheduler Service */
-       WMI_SERVICE_CSA_OFFLOAD,          /* CSA offload service */
-       WMI_SERVICE_CHATTER,              /* Chatter service */
-       WMI_SERVICE_COEX_FREQAVOID,       /* FW report freq range to avoid */
-       WMI_SERVICE_PACKET_POWER_SAVE,    /* packet power save service */
-       WMI_SERVICE_FORCE_FW_HANG,        /* To test fw recovery mechanism */
-       WMI_SERVICE_GPIO,                 /* GPIO service */
-       WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM, /* Modulated DTIM support */
-       WMI_STA_UAPSD_BASIC_AUTO_TRIG,    /* UAPSD AC Trigger Generation  */
-       WMI_STA_UAPSD_VAR_AUTO_TRIG,      /* -do- */
-       WMI_SERVICE_STA_KEEP_ALIVE,       /* STA keep alive mechanism support */
-       WMI_SERVICE_TX_ENCAP,             /* Packet type for TX encapsulation */
-
-       WMI_SERVICE_LAST,
-       WMI_MAX_SERVICE = 64              /* max service */
+enum wmi_service {
+       WMI_SERVICE_BEACON_OFFLOAD = 0,
+       WMI_SERVICE_SCAN_OFFLOAD,
+       WMI_SERVICE_ROAM_OFFLOAD,
+       WMI_SERVICE_BCN_MISS_OFFLOAD,
+       WMI_SERVICE_STA_PWRSAVE,
+       WMI_SERVICE_STA_ADVANCED_PWRSAVE,
+       WMI_SERVICE_AP_UAPSD,
+       WMI_SERVICE_AP_DFS,
+       WMI_SERVICE_11AC,
+       WMI_SERVICE_BLOCKACK,
+       WMI_SERVICE_PHYERR,
+       WMI_SERVICE_BCN_FILTER,
+       WMI_SERVICE_RTT,
+       WMI_SERVICE_RATECTRL,
+       WMI_SERVICE_WOW,
+       WMI_SERVICE_RATECTRL_CACHE,
+       WMI_SERVICE_IRAM_TIDS,
+       WMI_SERVICE_ARPNS_OFFLOAD,
+       WMI_SERVICE_NLO,
+       WMI_SERVICE_GTK_OFFLOAD,
+       WMI_SERVICE_SCAN_SCH,
+       WMI_SERVICE_CSA_OFFLOAD,
+       WMI_SERVICE_CHATTER,
+       WMI_SERVICE_COEX_FREQAVOID,
+       WMI_SERVICE_PACKET_POWER_SAVE,
+       WMI_SERVICE_FORCE_FW_HANG,
+       WMI_SERVICE_GPIO,
+       WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM,
+       WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG,
+       WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG,
+       WMI_SERVICE_STA_KEEP_ALIVE,
+       WMI_SERVICE_TX_ENCAP,
+       WMI_SERVICE_BURST,
+       WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT,
+       WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT,
+};
+
+enum wmi_10x_service {
+       WMI_10X_SERVICE_BEACON_OFFLOAD = 0,
+       WMI_10X_SERVICE_SCAN_OFFLOAD,
+       WMI_10X_SERVICE_ROAM_OFFLOAD,
+       WMI_10X_SERVICE_BCN_MISS_OFFLOAD,
+       WMI_10X_SERVICE_STA_PWRSAVE,
+       WMI_10X_SERVICE_STA_ADVANCED_PWRSAVE,
+       WMI_10X_SERVICE_AP_UAPSD,
+       WMI_10X_SERVICE_AP_DFS,
+       WMI_10X_SERVICE_11AC,
+       WMI_10X_SERVICE_BLOCKACK,
+       WMI_10X_SERVICE_PHYERR,
+       WMI_10X_SERVICE_BCN_FILTER,
+       WMI_10X_SERVICE_RTT,
+       WMI_10X_SERVICE_RATECTRL,
+       WMI_10X_SERVICE_WOW,
+       WMI_10X_SERVICE_RATECTRL_CACHE,
+       WMI_10X_SERVICE_IRAM_TIDS,
+       WMI_10X_SERVICE_BURST,
+
+       /* introduced in 10.2 */
+       WMI_10X_SERVICE_SMART_ANTENNA_SW_SUPPORT,
+       WMI_10X_SERVICE_FORCE_FW_HANG,
+       WMI_10X_SERVICE_SMART_ANTENNA_HW_SUPPORT,
+};
+
+enum wmi_main_service {
+       WMI_MAIN_SERVICE_BEACON_OFFLOAD = 0,
+       WMI_MAIN_SERVICE_SCAN_OFFLOAD,
+       WMI_MAIN_SERVICE_ROAM_OFFLOAD,
+       WMI_MAIN_SERVICE_BCN_MISS_OFFLOAD,
+       WMI_MAIN_SERVICE_STA_PWRSAVE,
+       WMI_MAIN_SERVICE_STA_ADVANCED_PWRSAVE,
+       WMI_MAIN_SERVICE_AP_UAPSD,
+       WMI_MAIN_SERVICE_AP_DFS,
+       WMI_MAIN_SERVICE_11AC,
+       WMI_MAIN_SERVICE_BLOCKACK,
+       WMI_MAIN_SERVICE_PHYERR,
+       WMI_MAIN_SERVICE_BCN_FILTER,
+       WMI_MAIN_SERVICE_RTT,
+       WMI_MAIN_SERVICE_RATECTRL,
+       WMI_MAIN_SERVICE_WOW,
+       WMI_MAIN_SERVICE_RATECTRL_CACHE,
+       WMI_MAIN_SERVICE_IRAM_TIDS,
+       WMI_MAIN_SERVICE_ARPNS_OFFLOAD,
+       WMI_MAIN_SERVICE_NLO,
+       WMI_MAIN_SERVICE_GTK_OFFLOAD,
+       WMI_MAIN_SERVICE_SCAN_SCH,
+       WMI_MAIN_SERVICE_CSA_OFFLOAD,
+       WMI_MAIN_SERVICE_CHATTER,
+       WMI_MAIN_SERVICE_COEX_FREQAVOID,
+       WMI_MAIN_SERVICE_PACKET_POWER_SAVE,
+       WMI_MAIN_SERVICE_FORCE_FW_HANG,
+       WMI_MAIN_SERVICE_GPIO,
+       WMI_MAIN_SERVICE_STA_DTIM_PS_MODULATED_DTIM,
+       WMI_MAIN_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG,
+       WMI_MAIN_SERVICE_STA_UAPSD_VAR_AUTO_TRIG,
+       WMI_MAIN_SERVICE_STA_KEEP_ALIVE,
+       WMI_MAIN_SERVICE_TX_ENCAP,
 };
 
 static inline char *wmi_service_name(int service_id)
 {
+#define SVCSTR(x) case x: return #x
+
        switch (service_id) {
-       case WMI_SERVICE_BEACON_OFFLOAD:
-               return "BEACON_OFFLOAD";
-       case WMI_SERVICE_SCAN_OFFLOAD:
-               return "SCAN_OFFLOAD";
-       case WMI_SERVICE_ROAM_OFFLOAD:
-               return "ROAM_OFFLOAD";
-       case WMI_SERVICE_BCN_MISS_OFFLOAD:
-               return "BCN_MISS_OFFLOAD";
-       case WMI_SERVICE_STA_PWRSAVE:
-               return "STA_PWRSAVE";
-       case WMI_SERVICE_STA_ADVANCED_PWRSAVE:
-               return "STA_ADVANCED_PWRSAVE";
-       case WMI_SERVICE_AP_UAPSD:
-               return "AP_UAPSD";
-       case WMI_SERVICE_AP_DFS:
-               return "AP_DFS";
-       case WMI_SERVICE_11AC:
-               return "11AC";
-       case WMI_SERVICE_BLOCKACK:
-               return "BLOCKACK";
-       case WMI_SERVICE_PHYERR:
-               return "PHYERR";
-       case WMI_SERVICE_BCN_FILTER:
-               return "BCN_FILTER";
-       case WMI_SERVICE_RTT:
-               return "RTT";
-       case WMI_SERVICE_RATECTRL:
-               return "RATECTRL";
-       case WMI_SERVICE_WOW:
-               return "WOW";
-       case WMI_SERVICE_RATECTRL_CACHE:
-               return "RATECTRL CACHE";
-       case WMI_SERVICE_IRAM_TIDS:
-               return "IRAM TIDS";
-       case WMI_SERVICE_ARPNS_OFFLOAD:
-               return "ARPNS_OFFLOAD";
-       case WMI_SERVICE_NLO:
-               return "NLO";
-       case WMI_SERVICE_GTK_OFFLOAD:
-               return "GTK_OFFLOAD";
-       case WMI_SERVICE_SCAN_SCH:
-               return "SCAN_SCH";
-       case WMI_SERVICE_CSA_OFFLOAD:
-               return "CSA_OFFLOAD";
-       case WMI_SERVICE_CHATTER:
-               return "CHATTER";
-       case WMI_SERVICE_COEX_FREQAVOID:
-               return "COEX_FREQAVOID";
-       case WMI_SERVICE_PACKET_POWER_SAVE:
-               return "PACKET_POWER_SAVE";
-       case WMI_SERVICE_FORCE_FW_HANG:
-               return "FORCE FW HANG";
-       case WMI_SERVICE_GPIO:
-               return "GPIO";
-       case WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM:
-               return "MODULATED DTIM";
-       case WMI_STA_UAPSD_BASIC_AUTO_TRIG:
-               return "BASIC UAPSD";
-       case WMI_STA_UAPSD_VAR_AUTO_TRIG:
-               return "VAR UAPSD";
-       case WMI_SERVICE_STA_KEEP_ALIVE:
-               return "STA KEEP ALIVE";
-       case WMI_SERVICE_TX_ENCAP:
-               return "TX ENCAP";
+       SVCSTR(WMI_SERVICE_BEACON_OFFLOAD);
+       SVCSTR(WMI_SERVICE_SCAN_OFFLOAD);
+       SVCSTR(WMI_SERVICE_ROAM_OFFLOAD);
+       SVCSTR(WMI_SERVICE_BCN_MISS_OFFLOAD);
+       SVCSTR(WMI_SERVICE_STA_PWRSAVE);
+       SVCSTR(WMI_SERVICE_STA_ADVANCED_PWRSAVE);
+       SVCSTR(WMI_SERVICE_AP_UAPSD);
+       SVCSTR(WMI_SERVICE_AP_DFS);
+       SVCSTR(WMI_SERVICE_11AC);
+       SVCSTR(WMI_SERVICE_BLOCKACK);
+       SVCSTR(WMI_SERVICE_PHYERR);
+       SVCSTR(WMI_SERVICE_BCN_FILTER);
+       SVCSTR(WMI_SERVICE_RTT);
+       SVCSTR(WMI_SERVICE_RATECTRL);
+       SVCSTR(WMI_SERVICE_WOW);
+       SVCSTR(WMI_SERVICE_RATECTRL_CACHE);
+       SVCSTR(WMI_SERVICE_IRAM_TIDS);
+       SVCSTR(WMI_SERVICE_ARPNS_OFFLOAD);
+       SVCSTR(WMI_SERVICE_NLO);
+       SVCSTR(WMI_SERVICE_GTK_OFFLOAD);
+       SVCSTR(WMI_SERVICE_SCAN_SCH);
+       SVCSTR(WMI_SERVICE_CSA_OFFLOAD);
+       SVCSTR(WMI_SERVICE_CHATTER);
+       SVCSTR(WMI_SERVICE_COEX_FREQAVOID);
+       SVCSTR(WMI_SERVICE_PACKET_POWER_SAVE);
+       SVCSTR(WMI_SERVICE_FORCE_FW_HANG);
+       SVCSTR(WMI_SERVICE_GPIO);
+       SVCSTR(WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM);
+       SVCSTR(WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG);
+       SVCSTR(WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG);
+       SVCSTR(WMI_SERVICE_STA_KEEP_ALIVE);
+       SVCSTR(WMI_SERVICE_TX_ENCAP);
+       SVCSTR(WMI_SERVICE_BURST);
+       SVCSTR(WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT);
+       SVCSTR(WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT);
        default:
-               return "UNKNOWN SERVICE\n";
+               return NULL;
        }
+
+#undef SVCSTR
+}
+
+#define WMI_MAX_SERVICE 64
+
+#define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id) \
+       (__le32_to_cpu((wmi_svc_bmap)[(svc_id)/(sizeof(u32))]) & \
+        BIT((svc_id)%(sizeof(u32))))
+
+#define SVCMAP(x, y) \
+       do { \
+               if (WMI_SERVICE_IS_ENABLED((in), (x))) \
+                       __set_bit(y, out); \
+       } while (0)
+
+static inline void wmi_10x_svc_map(const __le32 *in, unsigned long *out)
+{
+       SVCMAP(WMI_10X_SERVICE_BEACON_OFFLOAD,
+              WMI_SERVICE_BEACON_OFFLOAD);
+       SVCMAP(WMI_10X_SERVICE_SCAN_OFFLOAD,
+              WMI_SERVICE_SCAN_OFFLOAD);
+       SVCMAP(WMI_10X_SERVICE_ROAM_OFFLOAD,
+              WMI_SERVICE_ROAM_OFFLOAD);
+       SVCMAP(WMI_10X_SERVICE_BCN_MISS_OFFLOAD,
+              WMI_SERVICE_BCN_MISS_OFFLOAD);
+       SVCMAP(WMI_10X_SERVICE_STA_PWRSAVE,
+              WMI_SERVICE_STA_PWRSAVE);
+       SVCMAP(WMI_10X_SERVICE_STA_ADVANCED_PWRSAVE,
+              WMI_SERVICE_STA_ADVANCED_PWRSAVE);
+       SVCMAP(WMI_10X_SERVICE_AP_UAPSD,
+              WMI_SERVICE_AP_UAPSD);
+       SVCMAP(WMI_10X_SERVICE_AP_DFS,
+              WMI_SERVICE_AP_DFS);
+       SVCMAP(WMI_10X_SERVICE_11AC,
+              WMI_SERVICE_11AC);
+       SVCMAP(WMI_10X_SERVICE_BLOCKACK,
+              WMI_SERVICE_BLOCKACK);
+       SVCMAP(WMI_10X_SERVICE_PHYERR,
+              WMI_SERVICE_PHYERR);
+       SVCMAP(WMI_10X_SERVICE_BCN_FILTER,
+              WMI_SERVICE_BCN_FILTER);
+       SVCMAP(WMI_10X_SERVICE_RTT,
+              WMI_SERVICE_RTT);
+       SVCMAP(WMI_10X_SERVICE_RATECTRL,
+              WMI_SERVICE_RATECTRL);
+       SVCMAP(WMI_10X_SERVICE_WOW,
+              WMI_SERVICE_WOW);
+       SVCMAP(WMI_10X_SERVICE_RATECTRL_CACHE,
+              WMI_SERVICE_RATECTRL_CACHE);
+       SVCMAP(WMI_10X_SERVICE_IRAM_TIDS,
+              WMI_SERVICE_IRAM_TIDS);
+       SVCMAP(WMI_10X_SERVICE_BURST,
+              WMI_SERVICE_BURST);
+       SVCMAP(WMI_10X_SERVICE_SMART_ANTENNA_SW_SUPPORT,
+              WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT);
+       SVCMAP(WMI_10X_SERVICE_FORCE_FW_HANG,
+              WMI_SERVICE_FORCE_FW_HANG);
+       SVCMAP(WMI_10X_SERVICE_SMART_ANTENNA_HW_SUPPORT,
+              WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT);
+}
+
+static inline void wmi_main_svc_map(const __le32 *in, unsigned long *out)
+{
+       SVCMAP(WMI_MAIN_SERVICE_BEACON_OFFLOAD,
+              WMI_SERVICE_BEACON_OFFLOAD);
+       SVCMAP(WMI_MAIN_SERVICE_SCAN_OFFLOAD,
+              WMI_SERVICE_SCAN_OFFLOAD);
+       SVCMAP(WMI_MAIN_SERVICE_ROAM_OFFLOAD,
+              WMI_SERVICE_ROAM_OFFLOAD);
+       SVCMAP(WMI_MAIN_SERVICE_BCN_MISS_OFFLOAD,
+              WMI_SERVICE_BCN_MISS_OFFLOAD);
+       SVCMAP(WMI_MAIN_SERVICE_STA_PWRSAVE,
+              WMI_SERVICE_STA_PWRSAVE);
+       SVCMAP(WMI_MAIN_SERVICE_STA_ADVANCED_PWRSAVE,
+              WMI_SERVICE_STA_ADVANCED_PWRSAVE);
+       SVCMAP(WMI_MAIN_SERVICE_AP_UAPSD,
+              WMI_SERVICE_AP_UAPSD);
+       SVCMAP(WMI_MAIN_SERVICE_AP_DFS,
+              WMI_SERVICE_AP_DFS);
+       SVCMAP(WMI_MAIN_SERVICE_11AC,
+              WMI_SERVICE_11AC);
+       SVCMAP(WMI_MAIN_SERVICE_BLOCKACK,
+              WMI_SERVICE_BLOCKACK);
+       SVCMAP(WMI_MAIN_SERVICE_PHYERR,
+              WMI_SERVICE_PHYERR);
+       SVCMAP(WMI_MAIN_SERVICE_BCN_FILTER,
+              WMI_SERVICE_BCN_FILTER);
+       SVCMAP(WMI_MAIN_SERVICE_RTT,
+              WMI_SERVICE_RTT);
+       SVCMAP(WMI_MAIN_SERVICE_RATECTRL,
+              WMI_SERVICE_RATECTRL);
+       SVCMAP(WMI_MAIN_SERVICE_WOW,
+              WMI_SERVICE_WOW);
+       SVCMAP(WMI_MAIN_SERVICE_RATECTRL_CACHE,
+              WMI_SERVICE_RATECTRL_CACHE);
+       SVCMAP(WMI_MAIN_SERVICE_IRAM_TIDS,
+              WMI_SERVICE_IRAM_TIDS);
+       SVCMAP(WMI_MAIN_SERVICE_ARPNS_OFFLOAD,
+              WMI_SERVICE_ARPNS_OFFLOAD);
+       SVCMAP(WMI_MAIN_SERVICE_NLO,
+              WMI_SERVICE_NLO);
+       SVCMAP(WMI_MAIN_SERVICE_GTK_OFFLOAD,
+              WMI_SERVICE_GTK_OFFLOAD);
+       SVCMAP(WMI_MAIN_SERVICE_SCAN_SCH,
+              WMI_SERVICE_SCAN_SCH);
+       SVCMAP(WMI_MAIN_SERVICE_CSA_OFFLOAD,
+              WMI_SERVICE_CSA_OFFLOAD);
+       SVCMAP(WMI_MAIN_SERVICE_CHATTER,
+              WMI_SERVICE_CHATTER);
+       SVCMAP(WMI_MAIN_SERVICE_COEX_FREQAVOID,
+              WMI_SERVICE_COEX_FREQAVOID);
+       SVCMAP(WMI_MAIN_SERVICE_PACKET_POWER_SAVE,
+              WMI_SERVICE_PACKET_POWER_SAVE);
+       SVCMAP(WMI_MAIN_SERVICE_FORCE_FW_HANG,
+              WMI_SERVICE_FORCE_FW_HANG);
+       SVCMAP(WMI_MAIN_SERVICE_GPIO,
+              WMI_SERVICE_GPIO);
+       SVCMAP(WMI_MAIN_SERVICE_STA_DTIM_PS_MODULATED_DTIM,
+              WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM);
+       SVCMAP(WMI_MAIN_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG,
+              WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG);
+       SVCMAP(WMI_MAIN_SERVICE_STA_UAPSD_VAR_AUTO_TRIG,
+              WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG);
+       SVCMAP(WMI_MAIN_SERVICE_STA_KEEP_ALIVE,
+              WMI_SERVICE_STA_KEEP_ALIVE);
+       SVCMAP(WMI_MAIN_SERVICE_TX_ENCAP,
+              WMI_SERVICE_TX_ENCAP);
 }
 
+#undef SVCMAP
 
 #define WMI_SERVICE_BM_SIZE \
        ((WMI_MAX_SERVICE + sizeof(u32) - 1)/sizeof(u32))
@@ -803,6 +966,159 @@ enum wmi_10x_event_id {
        WMI_10X_PDEV_UTF_EVENTID = WMI_10X_END_EVENTID-1,
 };
 
+enum wmi_10_2_cmd_id {
+       WMI_10_2_START_CMDID = 0x9000,
+       WMI_10_2_END_CMDID = 0x9FFF,
+       WMI_10_2_INIT_CMDID,
+       WMI_10_2_START_SCAN_CMDID = WMI_10_2_START_CMDID,
+       WMI_10_2_STOP_SCAN_CMDID,
+       WMI_10_2_SCAN_CHAN_LIST_CMDID,
+       WMI_10_2_ECHO_CMDID,
+       WMI_10_2_PDEV_SET_REGDOMAIN_CMDID,
+       WMI_10_2_PDEV_SET_CHANNEL_CMDID,
+       WMI_10_2_PDEV_SET_PARAM_CMDID,
+       WMI_10_2_PDEV_PKTLOG_ENABLE_CMDID,
+       WMI_10_2_PDEV_PKTLOG_DISABLE_CMDID,
+       WMI_10_2_PDEV_SET_WMM_PARAMS_CMDID,
+       WMI_10_2_PDEV_SET_HT_CAP_IE_CMDID,
+       WMI_10_2_PDEV_SET_VHT_CAP_IE_CMDID,
+       WMI_10_2_PDEV_SET_BASE_MACADDR_CMDID,
+       WMI_10_2_PDEV_SET_QUIET_MODE_CMDID,
+       WMI_10_2_PDEV_GREEN_AP_PS_ENABLE_CMDID,
+       WMI_10_2_PDEV_GET_TPC_CONFIG_CMDID,
+       WMI_10_2_VDEV_CREATE_CMDID,
+       WMI_10_2_VDEV_DELETE_CMDID,
+       WMI_10_2_VDEV_START_REQUEST_CMDID,
+       WMI_10_2_VDEV_RESTART_REQUEST_CMDID,
+       WMI_10_2_VDEV_UP_CMDID,
+       WMI_10_2_VDEV_STOP_CMDID,
+       WMI_10_2_VDEV_DOWN_CMDID,
+       WMI_10_2_VDEV_STANDBY_RESPONSE_CMDID,
+       WMI_10_2_VDEV_RESUME_RESPONSE_CMDID,
+       WMI_10_2_VDEV_SET_PARAM_CMDID,
+       WMI_10_2_VDEV_INSTALL_KEY_CMDID,
+       WMI_10_2_VDEV_SET_DSCP_TID_MAP_CMDID,
+       WMI_10_2_PEER_CREATE_CMDID,
+       WMI_10_2_PEER_DELETE_CMDID,
+       WMI_10_2_PEER_FLUSH_TIDS_CMDID,
+       WMI_10_2_PEER_SET_PARAM_CMDID,
+       WMI_10_2_PEER_ASSOC_CMDID,
+       WMI_10_2_PEER_ADD_WDS_ENTRY_CMDID,
+       WMI_10_2_PEER_UPDATE_WDS_ENTRY_CMDID,
+       WMI_10_2_PEER_REMOVE_WDS_ENTRY_CMDID,
+       WMI_10_2_PEER_MCAST_GROUP_CMDID,
+       WMI_10_2_BCN_TX_CMDID,
+       WMI_10_2_BCN_PRB_TMPL_CMDID,
+       WMI_10_2_BCN_FILTER_RX_CMDID,
+       WMI_10_2_PRB_REQ_FILTER_RX_CMDID,
+       WMI_10_2_MGMT_TX_CMDID,
+       WMI_10_2_ADDBA_CLEAR_RESP_CMDID,
+       WMI_10_2_ADDBA_SEND_CMDID,
+       WMI_10_2_ADDBA_STATUS_CMDID,
+       WMI_10_2_DELBA_SEND_CMDID,
+       WMI_10_2_ADDBA_SET_RESP_CMDID,
+       WMI_10_2_SEND_SINGLEAMSDU_CMDID,
+       WMI_10_2_STA_POWERSAVE_MODE_CMDID,
+       WMI_10_2_STA_POWERSAVE_PARAM_CMDID,
+       WMI_10_2_STA_MIMO_PS_MODE_CMDID,
+       WMI_10_2_DBGLOG_CFG_CMDID,
+       WMI_10_2_PDEV_DFS_ENABLE_CMDID,
+       WMI_10_2_PDEV_DFS_DISABLE_CMDID,
+       WMI_10_2_PDEV_QVIT_CMDID,
+       WMI_10_2_ROAM_SCAN_MODE,
+       WMI_10_2_ROAM_SCAN_RSSI_THRESHOLD,
+       WMI_10_2_ROAM_SCAN_PERIOD,
+       WMI_10_2_ROAM_SCAN_RSSI_CHANGE_THRESHOLD,
+       WMI_10_2_ROAM_AP_PROFILE,
+       WMI_10_2_OFL_SCAN_ADD_AP_PROFILE,
+       WMI_10_2_OFL_SCAN_REMOVE_AP_PROFILE,
+       WMI_10_2_OFL_SCAN_PERIOD,
+       WMI_10_2_P2P_DEV_SET_DEVICE_INFO,
+       WMI_10_2_P2P_DEV_SET_DISCOVERABILITY,
+       WMI_10_2_P2P_GO_SET_BEACON_IE,
+       WMI_10_2_P2P_GO_SET_PROBE_RESP_IE,
+       WMI_10_2_AP_PS_PEER_PARAM_CMDID,
+       WMI_10_2_AP_PS_PEER_UAPSD_COEX_CMDID,
+       WMI_10_2_PEER_RATE_RETRY_SCHED_CMDID,
+       WMI_10_2_WLAN_PROFILE_TRIGGER_CMDID,
+       WMI_10_2_WLAN_PROFILE_SET_HIST_INTVL_CMDID,
+       WMI_10_2_WLAN_PROFILE_GET_PROFILE_DATA_CMDID,
+       WMI_10_2_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID,
+       WMI_10_2_WLAN_PROFILE_LIST_PROFILE_ID_CMDID,
+       WMI_10_2_PDEV_SUSPEND_CMDID,
+       WMI_10_2_PDEV_RESUME_CMDID,
+       WMI_10_2_ADD_BCN_FILTER_CMDID,
+       WMI_10_2_RMV_BCN_FILTER_CMDID,
+       WMI_10_2_WOW_ADD_WAKE_PATTERN_CMDID,
+       WMI_10_2_WOW_DEL_WAKE_PATTERN_CMDID,
+       WMI_10_2_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID,
+       WMI_10_2_WOW_ENABLE_CMDID,
+       WMI_10_2_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID,
+       WMI_10_2_RTT_MEASREQ_CMDID,
+       WMI_10_2_RTT_TSF_CMDID,
+       WMI_10_2_RTT_KEEPALIVE_CMDID,
+       WMI_10_2_PDEV_SEND_BCN_CMDID,
+       WMI_10_2_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID,
+       WMI_10_2_VDEV_SPECTRAL_SCAN_ENABLE_CMDID,
+       WMI_10_2_REQUEST_STATS_CMDID,
+       WMI_10_2_GPIO_CONFIG_CMDID,
+       WMI_10_2_GPIO_OUTPUT_CMDID,
+       WMI_10_2_VDEV_RATEMASK_CMDID,
+       WMI_10_2_PDEV_SMART_ANT_ENABLE_CMDID,
+       WMI_10_2_PDEV_SMART_ANT_SET_RX_ANTENNA_CMDID,
+       WMI_10_2_PEER_SMART_ANT_SET_TX_ANTENNA_CMDID,
+       WMI_10_2_PEER_SMART_ANT_SET_TRAIN_INFO_CMDID,
+       WMI_10_2_PEER_SMART_ANT_SET_NODE_CONFIG_OPS_CMDID,
+       WMI_10_2_FORCE_FW_HANG_CMDID,
+       WMI_10_2_PDEV_SET_ANTENNA_SWITCH_TABLE_CMDID,
+       WMI_10_2_PDEV_SET_CTL_TABLE_CMDID,
+       WMI_10_2_PDEV_SET_MIMOGAIN_TABLE_CMDID,
+       WMI_10_2_PDEV_RATEPWR_TABLE_CMDID,
+       WMI_10_2_PDEV_RATEPWR_CHAINMSK_TABLE_CMDID,
+       WMI_10_2_PDEV_UTF_CMDID = WMI_10_2_END_CMDID - 1,
+};
+
+enum wmi_10_2_event_id {
+       WMI_10_2_SERVICE_READY_EVENTID = 0x8000,
+       WMI_10_2_READY_EVENTID,
+       WMI_10_2_DEBUG_MESG_EVENTID,
+       WMI_10_2_START_EVENTID = 0x9000,
+       WMI_10_2_END_EVENTID = 0x9FFF,
+       WMI_10_2_SCAN_EVENTID = WMI_10_2_START_EVENTID,
+       WMI_10_2_ECHO_EVENTID,
+       WMI_10_2_UPDATE_STATS_EVENTID,
+       WMI_10_2_INST_RSSI_STATS_EVENTID,
+       WMI_10_2_VDEV_START_RESP_EVENTID,
+       WMI_10_2_VDEV_STANDBY_REQ_EVENTID,
+       WMI_10_2_VDEV_RESUME_REQ_EVENTID,
+       WMI_10_2_VDEV_STOPPED_EVENTID,
+       WMI_10_2_PEER_STA_KICKOUT_EVENTID,
+       WMI_10_2_HOST_SWBA_EVENTID,
+       WMI_10_2_TBTTOFFSET_UPDATE_EVENTID,
+       WMI_10_2_MGMT_RX_EVENTID,
+       WMI_10_2_CHAN_INFO_EVENTID,
+       WMI_10_2_PHYERR_EVENTID,
+       WMI_10_2_ROAM_EVENTID,
+       WMI_10_2_PROFILE_MATCH,
+       WMI_10_2_DEBUG_PRINT_EVENTID,
+       WMI_10_2_PDEV_QVIT_EVENTID,
+       WMI_10_2_WLAN_PROFILE_DATA_EVENTID,
+       WMI_10_2_RTT_MEASUREMENT_REPORT_EVENTID,
+       WMI_10_2_TSF_MEASUREMENT_REPORT_EVENTID,
+       WMI_10_2_RTT_ERROR_REPORT_EVENTID,
+       WMI_10_2_RTT_KEEPALIVE_EVENTID,
+       WMI_10_2_WOW_WAKEUP_HOST_EVENTID,
+       WMI_10_2_DCS_INTERFERENCE_EVENTID,
+       WMI_10_2_PDEV_TPC_CONFIG_EVENTID,
+       WMI_10_2_GPIO_INPUT_EVENTID,
+       WMI_10_2_PEER_RATECODE_LIST_EVENTID,
+       WMI_10_2_GENERIC_BUFFER_EVENTID,
+       WMI_10_2_MCAST_BUF_RELEASE_EVENTID,
+       WMI_10_2_MCAST_LIST_AGEOUT_EVENTID,
+       WMI_10_2_WDS_PEER_EVENTID,
+       WMI_10_2_PDEV_UTF_EVENTID = WMI_10_2_END_EVENTID - 1,
+};
+
 enum wmi_phy_mode {
        MODE_11A        = 0,   /* 11a Mode */
        MODE_11G        = 1,   /* 11b/g Mode */
@@ -1076,10 +1392,6 @@ struct wlan_host_mem_req {
        __le32 num_units;
 } __packed;
 
-#define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id) \
-       ((((wmi_svc_bmap)[(svc_id)/(sizeof(u32))]) & \
-       (1 << ((svc_id)%(sizeof(u32))))) != 0)
-
 /*
  * The following struct holds optional payload for
  * wmi_service_ready_event,e.g., 11ac pass some of the
@@ -1551,6 +1863,16 @@ struct wmi_resource_config_10x {
        __le32 max_frag_entries;
 } __packed;
 
+struct wmi_resource_config_10_2 {
+       struct wmi_resource_config_10x common;
+       __le32 max_peer_ext_stats;
+       __le32 smart_ant_cap; /* 0-disable, 1-enable */
+       __le32 bk_min_free;
+       __le32 be_min_free;
+       __le32 vi_min_free;
+       __le32 vo_min_free;
+       __le32 rx_batchmode; /* 0-disable, 1-enable */
+} __packed;
 
 #define NUM_UNITS_IS_NUM_VDEVS   0x1
 #define NUM_UNITS_IS_NUM_PEERS   0x2
@@ -1588,11 +1910,28 @@ struct wmi_init_cmd_10x {
        struct host_memory_chunk host_mem_chunks[1];
 } __packed;
 
+struct wmi_init_cmd_10_2 {
+       struct wmi_resource_config_10_2 resource_config;
+       __le32 num_host_mem_chunks;
+
+       /*
+        * variable number of host memory chunks.
+        * This should be the last element in the structure
+        */
+       struct host_memory_chunk host_mem_chunks[1];
+} __packed;
+
+struct wmi_chan_list_entry {
+       __le16 freq;
+       u8 phy_mode; /* valid for 10.2 only */
+       u8 reserved;
+} __packed;
+
 /* TLV for channel list */
 struct wmi_chan_list {
        __le32 tag; /* WMI_CHAN_LIST_TAG */
        __le32 num_chan;
-       __le32 channel_list[0];
+       struct wmi_chan_list_entry channel_list[0];
 } __packed;
 
 struct wmi_bssid_list {
@@ -1821,7 +2160,7 @@ struct wmi_start_scan_arg {
        u32 n_bssids;
 
        u8 ie[WLAN_SCAN_PARAMS_MAX_IE_LEN];
-       u32 channels[64];
+       u16 channels[64];
        struct wmi_ssid_arg ssids[WLAN_SCAN_PARAMS_MAX_SSID];
        struct wmi_bssid_arg bssids[WLAN_SCAN_PARAMS_MAX_BSSID];
 };
@@ -2067,6 +2406,7 @@ struct wmi_comb_phyerr_rx_event {
 #define PHYERR_TLV_SIG                         0xBB
 #define PHYERR_TLV_TAG_SEARCH_FFT_REPORT       0xFB
 #define PHYERR_TLV_TAG_RADAR_PULSE_SUMMARY     0xF8
+#define PHYERR_TLV_TAG_SPECTRAL_SUMMARY_REPORT 0xF9
 
 struct phyerr_radar_report {
        __le32 reg0; /* RADAR_REPORT_REG0_* */
@@ -2515,6 +2855,19 @@ enum wmi_10x_pdev_param {
        WMI_10X_PDEV_PARAM_BURST_DUR,
        /* Set Bursting Enable*/
        WMI_10X_PDEV_PARAM_BURST_ENABLE,
+
+       /* following are available as of firmware 10.2 */
+       WMI_10X_PDEV_PARAM_SMART_ANTENNA_DEFAULT_ANTENNA,
+       WMI_10X_PDEV_PARAM_IGMPMLD_OVERRIDE,
+       WMI_10X_PDEV_PARAM_IGMPMLD_TID,
+       WMI_10X_PDEV_PARAM_ANTENNA_GAIN,
+       WMI_10X_PDEV_PARAM_RX_DECAP_MODE,
+       WMI_10X_PDEV_PARAM_RX_FILTER,
+       WMI_10X_PDEV_PARAM_SET_MCAST_TO_UCAST_TID,
+       WMI_10X_PDEV_PARAM_PROXY_STA_MODE,
+       WMI_10X_PDEV_PARAM_SET_MCAST2UCAST_MODE,
+       WMI_10X_PDEV_PARAM_SET_MCAST2UCAST_BUFFER,
+       WMI_10X_PDEV_PARAM_REMOVE_MCAST2UCAST_BUFFER,
 };
 
 struct wmi_pdev_set_param_cmd {
@@ -3387,6 +3740,14 @@ enum wmi_10x_vdev_param {
        WMI_10X_VDEV_PARAM_ENABLE_RTSCTS,
 
        WMI_10X_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS,
+
+       /* following are available as of firmware 10.2 */
+       WMI_10X_VDEV_PARAM_TX_ENCAP_TYPE,
+       WMI_10X_VDEV_PARAM_CABQ_MAXDUR,
+       WMI_10X_VDEV_PARAM_MFPTEST_SET,
+       WMI_10X_VDEV_PARAM_RTS_FIXED_RATE,
+       WMI_10X_VDEV_PARAM_VHT_SGIMASK,
+       WMI_10X_VDEV_PARAM_VHT80_RATEMASK,
 };
 
 /* slot time long */
@@ -3444,6 +3805,98 @@ struct wmi_vdev_simple_event {
 /* unsupported VDEV combination */
 #define WMI_INIFIED_VDEV_START_RESPONSE_NOT_SUPPORTED  0x2
 
+/* TODO: please add more comments if you have in-depth information */
+struct wmi_vdev_spectral_conf_cmd {
+       __le32 vdev_id;
+
+       /* number of fft samples to send (0 for infinite) */
+       __le32 scan_count;
+       __le32 scan_period;
+       __le32 scan_priority;
+
+       /* number of bins in the FFT: 2^(fft_size - bin_scale) */
+       __le32 scan_fft_size;
+       __le32 scan_gc_ena;
+       __le32 scan_restart_ena;
+       __le32 scan_noise_floor_ref;
+       __le32 scan_init_delay;
+       __le32 scan_nb_tone_thr;
+       __le32 scan_str_bin_thr;
+       __le32 scan_wb_rpt_mode;
+       __le32 scan_rssi_rpt_mode;
+       __le32 scan_rssi_thr;
+       __le32 scan_pwr_format;
+
+       /* rpt_mode: Format of FFT report to software for spectral scan
+        * triggered FFTs:
+        *      0: No FFT report (only spectral scan summary report)
+        *      1: 2-dword summary of metrics for each completed FFT + spectral
+        *         scan summary report
+        *      2: 2-dword summary of metrics for each completed FFT +
+        *         1x- oversampled bins(in-band) per FFT + spectral scan summary
+        *         report
+        *      3: 2-dword summary of metrics for each completed FFT +
+        *         2x- oversampled bins (all) per FFT + spectral scan summary
+        */
+       __le32 scan_rpt_mode;
+       __le32 scan_bin_scale;
+       __le32 scan_dbm_adj;
+       __le32 scan_chn_mask;
+} __packed;
+
+struct wmi_vdev_spectral_conf_arg {
+       u32 vdev_id;
+       u32 scan_count;
+       u32 scan_period;
+       u32 scan_priority;
+       u32 scan_fft_size;
+       u32 scan_gc_ena;
+       u32 scan_restart_ena;
+       u32 scan_noise_floor_ref;
+       u32 scan_init_delay;
+       u32 scan_nb_tone_thr;
+       u32 scan_str_bin_thr;
+       u32 scan_wb_rpt_mode;
+       u32 scan_rssi_rpt_mode;
+       u32 scan_rssi_thr;
+       u32 scan_pwr_format;
+       u32 scan_rpt_mode;
+       u32 scan_bin_scale;
+       u32 scan_dbm_adj;
+       u32 scan_chn_mask;
+};
+
+#define WMI_SPECTRAL_ENABLE_DEFAULT              0
+#define WMI_SPECTRAL_COUNT_DEFAULT               0
+#define WMI_SPECTRAL_PERIOD_DEFAULT             35
+#define WMI_SPECTRAL_PRIORITY_DEFAULT            1
+#define WMI_SPECTRAL_FFT_SIZE_DEFAULT            7
+#define WMI_SPECTRAL_GC_ENA_DEFAULT              1
+#define WMI_SPECTRAL_RESTART_ENA_DEFAULT         0
+#define WMI_SPECTRAL_NOISE_FLOOR_REF_DEFAULT   -96
+#define WMI_SPECTRAL_INIT_DELAY_DEFAULT         80
+#define WMI_SPECTRAL_NB_TONE_THR_DEFAULT        12
+#define WMI_SPECTRAL_STR_BIN_THR_DEFAULT         8
+#define WMI_SPECTRAL_WB_RPT_MODE_DEFAULT         0
+#define WMI_SPECTRAL_RSSI_RPT_MODE_DEFAULT       0
+#define WMI_SPECTRAL_RSSI_THR_DEFAULT         0xf0
+#define WMI_SPECTRAL_PWR_FORMAT_DEFAULT          0
+#define WMI_SPECTRAL_RPT_MODE_DEFAULT            2
+#define WMI_SPECTRAL_BIN_SCALE_DEFAULT           1
+#define WMI_SPECTRAL_DBM_ADJ_DEFAULT             1
+#define WMI_SPECTRAL_CHN_MASK_DEFAULT            1
+
+struct wmi_vdev_spectral_enable_cmd {
+       __le32 vdev_id;
+       __le32 trigger_cmd;
+       __le32 enable_cmd;
+} __packed;
+
+#define WMI_SPECTRAL_TRIGGER_CMD_TRIGGER  1
+#define WMI_SPECTRAL_TRIGGER_CMD_CLEAR    2
+#define WMI_SPECTRAL_ENABLE_CMD_ENABLE    1
+#define WMI_SPECTRAL_ENABLE_CMD_DISABLE   2
+
 /* Beacon processing related command and event structures */
 struct wmi_bcn_tx_hdr {
        __le32 vdev_id;
@@ -3470,6 +3923,11 @@ enum wmi_bcn_tx_ref_flags {
        WMI_BCN_TX_REF_FLAG_DELIVER_CAB = 0x2,
 };
 
+/* TODO: It is unclear why "no antenna" works while any other seemingly valid
+ * chainmask yields no beacons on the air at all.
+ */
+#define WMI_BCN_TX_REF_DEF_ANTENNA 0
+
 struct wmi_bcn_tx_ref_cmd {
        __le32 vdev_id;
        __le32 data_len;
@@ -3481,6 +3939,8 @@ struct wmi_bcn_tx_ref_cmd {
        __le32 frame_control;
        /* to control CABQ traffic: WMI_BCN_TX_REF_FLAG_ */
        __le32 flags;
+       /* introduced in 10.2 */
+       __le32 antenna_mask;
 } __packed;
 
 /* Beacon filter */
@@ -4053,7 +4513,7 @@ struct wmi_peer_set_q_empty_callback_cmd {
 /* Maximum listen interval supported by hw in units of beacon interval */
 #define ATH10K_MAX_HW_LISTEN_INTERVAL 5
 
-struct wmi_peer_assoc_complete_cmd {
+struct wmi_common_peer_assoc_complete_cmd {
        struct wmi_mac_addr peer_macaddr;
        __le32 vdev_id;
        __le32 peer_new_assoc; /* 1=assoc, 0=reassoc */
@@ -4071,11 +4531,30 @@ struct wmi_peer_assoc_complete_cmd {
        __le32 peer_vht_caps;
        __le32 peer_phymode;
        struct wmi_vht_rate_set peer_vht_rates;
+};
+
+struct wmi_main_peer_assoc_complete_cmd {
+       struct wmi_common_peer_assoc_complete_cmd cmd;
+
        /* HT Operation Element of the peer. Five bytes packed in 2
         *  INT32 array and filled from lsb to msb. */
        __le32 peer_ht_info[2];
 } __packed;
 
+struct wmi_10_1_peer_assoc_complete_cmd {
+       struct wmi_common_peer_assoc_complete_cmd cmd;
+} __packed;
+
+#define WMI_PEER_ASSOC_INFO0_MAX_MCS_IDX_LSB 0
+#define WMI_PEER_ASSOC_INFO0_MAX_MCS_IDX_MASK 0x0f
+#define WMI_PEER_ASSOC_INFO0_MAX_NSS_LSB 4
+#define WMI_PEER_ASSOC_INFO0_MAX_NSS_MASK 0xf0
+
+struct wmi_10_2_peer_assoc_complete_cmd {
+       struct wmi_common_peer_assoc_complete_cmd cmd;
+       __le32 info0; /* WMI_PEER_ASSOC_INFO0_ */
+} __packed;
+
 struct wmi_peer_assoc_complete_arg {
        u8 addr[ETH_ALEN];
        u32 vdev_id;
@@ -4290,6 +4769,10 @@ int ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id,
                              u32 param_id, u32 param_value);
 int ath10k_wmi_vdev_install_key(struct ath10k *ar,
                                const struct wmi_vdev_install_key_arg *arg);
+int ath10k_wmi_vdev_spectral_conf(struct ath10k *ar,
+                                 const struct wmi_vdev_spectral_conf_arg *arg);
+int ath10k_wmi_vdev_spectral_enable(struct ath10k *ar, u32 vdev_id, u32 trigger,
+                                   u32 enable);
 int ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id,
                    const u8 peer_addr[ETH_ALEN]);
 int ath10k_wmi_peer_delete(struct ath10k *ar, u32 vdev_id,
index 7106547a14ddc6819751b48041540ab3846e7f68..66b6366158b90a92054dbb9ce5cd97a665abc65c 100644 (file)
@@ -351,8 +351,7 @@ void ath5k_hw_deinit(struct ath5k_hw *ah)
 {
        __set_bit(ATH_STAT_INVALID, ah->status);
 
-       if (ah->ah_rf_banks != NULL)
-               kfree(ah->ah_rf_banks);
+       kfree(ah->ah_rf_banks);
 
        ath5k_eeprom_detach(ah);
 
index 8ad2550bce7ff4820511a606a30d10f81e09b91d..59a87247aac4ca5fe43eb55a5a3b60ae2f10adc2 100644 (file)
@@ -1423,7 +1423,7 @@ ath5k_receive_frame(struct ath5k_hw *ah, struct sk_buff *skb,
                break;
        }
 
-       if (rxs->rate_idx >= 0 && rs->rs_rate ==
+       if (rs->rs_rate ==
            ah->sbands[ah->curchan->band].bitrates[rxs->rate_idx].hw_value_short)
                rxs->flag |= RX_FLAG_SHORTPRE;
 
index b8d031ae63c2f8019a0c997295e52f9b2b01b46c..399728618fb9e2e414b3aa73460d146bb0ca9257 100644 (file)
@@ -62,6 +62,7 @@
 
 #include <linux/export.h>
 #include <linux/moduleparam.h>
+#include <linux/vmalloc.h>
 
 #include <linux/seq_file.h>
 #include <linux/list.h>
@@ -894,6 +895,100 @@ static const struct file_operations fops_queue = {
        .llseek = default_llseek,
 };
 
+/* debugfs: eeprom */
+
+struct eeprom_private {
+       u16 *buf;
+       int len;
+};
+
+static int open_file_eeprom(struct inode *inode, struct file *file)
+{
+       struct eeprom_private *ep;
+       struct ath5k_hw *ah = inode->i_private;
+       bool res;
+       int i, ret;
+       u32 eesize;
+       u16 val, *buf;
+
+       /* Get eeprom size */
+
+       res = ath5k_hw_nvram_read(ah, AR5K_EEPROM_SIZE_UPPER, &val);
+       if (!res)
+               return -EACCES;
+
+       if (val == 0) {
+               eesize = AR5K_EEPROM_INFO_MAX + AR5K_EEPROM_INFO_BASE;
+       } else {
+               eesize = (val & AR5K_EEPROM_SIZE_UPPER_MASK) <<
+                       AR5K_EEPROM_SIZE_ENDLOC_SHIFT;
+               ath5k_hw_nvram_read(ah, AR5K_EEPROM_SIZE_LOWER, &val);
+               eesize = eesize | val;
+       }
+
+       if (eesize > 4096)
+               return -EINVAL;
+
+       /* Create buffer and read in eeprom */
+
+       buf = vmalloc(eesize);
+       if (!buf) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       for (i = 0; i < eesize; ++i) {
+               AR5K_EEPROM_READ(i, val);
+               buf[i] = val;
+       }
+
+       /* Create private struct and assign to file */
+
+       ep = kmalloc(sizeof(*ep), GFP_KERNEL);
+       if (!ep) {
+               ret = -ENOMEM;
+               goto freebuf;
+       }
+
+       ep->buf = buf;
+       ep->len = i;
+
+       file->private_data = (void *)ep;
+
+       return 0;
+
+freebuf:
+       vfree(buf);
+err:
+       return ret;
+
+}
+
+static ssize_t read_file_eeprom(struct file *file, char __user *user_buf,
+                                  size_t count, loff_t *ppos)
+{
+       struct eeprom_private *ep = file->private_data;
+
+       return simple_read_from_buffer(user_buf, count, ppos, ep->buf, ep->len);
+}
+
+static int release_file_eeprom(struct inode *inode, struct file *file)
+{
+       struct eeprom_private *ep = file->private_data;
+
+       vfree(ep->buf);
+       kfree(ep);
+
+       return 0;
+}
+
+static const struct file_operations fops_eeprom = {
+       .open = open_file_eeprom,
+       .read = read_file_eeprom,
+       .release = release_file_eeprom,
+       .owner = THIS_MODULE,
+};
+
 
 void
 ath5k_debug_init_device(struct ath5k_hw *ah)
@@ -921,6 +1016,8 @@ ath5k_debug_init_device(struct ath5k_hw *ah)
 
        debugfs_create_file("misc", S_IRUSR, phydir, ah, &fops_misc);
 
+       debugfs_create_file("eeprom", S_IRUSR, phydir, ah, &fops_eeprom);
+
        debugfs_create_file("frameerrors", S_IWUSR | S_IRUSR, phydir, ah,
                            &fops_frameerrors);
 
index 48a6a69b57bcb6bcce63f23032e7ee629c124d90..2062d1190556b11983234b35c9a76e7cff893367 100644 (file)
@@ -130,6 +130,7 @@ ath5k_register_led(struct ath5k_hw *ah, struct ath5k_led *led,
 
        led->ah = ah;
        strncpy(led->name, name, sizeof(led->name));
+       led->name[sizeof(led->name)-1] = 0;
        led->led_dev.name = led->name;
        led->led_dev.default_trigger = trigger;
        led->led_dev.brightness_set = ath5k_led_brightness_set;
index e535807c3d8912863da3604dc9e698ee664f0a48..ba60e37213eb1d289fa983e8eacbce48c1616b0a 100644 (file)
@@ -717,6 +717,7 @@ ath6kl_add_bss_if_needed(struct ath6kl_vif *vif,
                memcpy(ie + 2, vif->ssid, vif->ssid_len);
                memcpy(ie + 2 + vif->ssid_len, beacon_ie, beacon_ie_len);
                bss = cfg80211_inform_bss(ar->wiphy, chan,
+                                         CFG80211_BSS_FTYPE_UNKNOWN,
                                          bssid, 0, cap_val, 100,
                                          ie, 2 + vif->ssid_len + beacon_ie_len,
                                          0, GFP_KERNEL);
index fffd52355123f31e7bae15561fd867297d73f924..6e473fa4b13cae0df30a33fd9162729afaf76f6b 100644 (file)
@@ -1049,7 +1049,7 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name)
                        ar->hw.reserved_ram_size = le32_to_cpup(val);
 
                        ath6kl_dbg(ATH6KL_DBG_BOOT,
-                                  "found reserved ram size ie 0x%d\n",
+                                  "found reserved ram size ie %d\n",
                                   ar->hw.reserved_ram_size);
                        break;
                case ATH6KL_FW_IE_CAPABILITIES:
index 21516bc657857b8a44405c5c22944a275271e5f2..933aef025698d90326f91b8d9746a417786769e1 100644 (file)
@@ -225,7 +225,7 @@ int ath6kl_diag_write32(struct ath6kl *ar, u32 address, __le32 value)
        ret = ath6kl_hif_diag_write32(ar, address, value);
 
        if (ret) {
-               ath6kl_err("failed to write 0x%x during diagnose window to 0x%d\n",
+               ath6kl_err("failed to write 0x%x during diagnose window to 0x%x\n",
                           address, value);
                return ret;
        }
index 339d89f14d32b1991c3d3d646f460b90f41411bb..eab0ab976af29ebb0b355f82b01caeb39bd07152 100644 (file)
@@ -1400,6 +1400,7 @@ static const struct sdio_device_id ath6kl_sdio_devices[] = {
        {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6003_BASE | 0x1))},
        {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x0))},
        {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x1))},
+       {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x2))},
        {},
 };
 
index c44325856b81fc4cee191ec9aceb2102f2f0b23b..a6a5e40b3e981453b72233e930e712c8412bf60e 100644 (file)
@@ -1229,26 +1229,7 @@ static struct usb_driver ath6kl_usb_driver = {
        .disable_hub_initiated_lpm = 1,
 };
 
-static int ath6kl_usb_init(void)
-{
-       int ret;
-
-       ret = usb_register(&ath6kl_usb_driver);
-       if (ret) {
-               ath6kl_err("usb registration failed: %d\n", ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-static void ath6kl_usb_exit(void)
-{
-       usb_deregister(&ath6kl_usb_driver);
-}
-
-module_init(ath6kl_usb_init);
-module_exit(ath6kl_usb_exit);
+module_usb_driver(ath6kl_usb_driver);
 
 MODULE_AUTHOR("Atheros Communications, Inc.");
 MODULE_DESCRIPTION("Driver support for Atheros AR600x USB devices");
index 94df345d08c24210fefe4b707079f85fe75e386f..b921005ad7eef7bb9ab25dedadf6c50f7ad85d26 100644 (file)
@@ -619,8 +619,7 @@ static int ath6kl_wmi_rx_probe_req_event_rx(struct wmi *wmi, u8 *datap, int len,
                   dlen, freq, vif->probe_req_report);
 
        if (vif->probe_req_report || vif->nw_type == AP_NETWORK)
-               cfg80211_rx_mgmt(&vif->wdev, freq, 0, ev->data, dlen, 0,
-                                GFP_ATOMIC);
+               cfg80211_rx_mgmt(&vif->wdev, freq, 0, ev->data, dlen, 0);
 
        return 0;
 }
@@ -659,7 +658,7 @@ static int ath6kl_wmi_rx_action_event_rx(struct wmi *wmi, u8 *datap, int len,
                return -EINVAL;
        }
        ath6kl_dbg(ATH6KL_DBG_WMI, "rx_action: len=%u freq=%u\n", dlen, freq);
-       cfg80211_rx_mgmt(&vif->wdev, freq, 0, ev->data, dlen, 0, GFP_ATOMIC);
+       cfg80211_rx_mgmt(&vif->wdev, freq, 0, ev->data, dlen, 0);
 
        return 0;
 }
@@ -1093,7 +1092,6 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len,
        u8 *buf;
        struct ieee80211_channel *channel;
        struct ath6kl *ar = wmi->parent_dev;
-       struct ieee80211_mgmt *mgmt;
        struct cfg80211_bss *bss;
 
        if (len <= sizeof(struct wmi_bss_info_hdr2))
@@ -1139,39 +1137,15 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len,
                }
        }
 
-       /*
-        * In theory, use of cfg80211_inform_bss() would be more natural here
-        * since we do not have the full frame. However, at least for now,
-        * cfg80211 can only distinguish Beacon and Probe Response frames from
-        * each other when using cfg80211_inform_bss_frame(), so let's build a
-        * fake IEEE 802.11 header to be able to take benefit of this.
-        */
-       mgmt = kmalloc(24 + len, GFP_ATOMIC);
-       if (mgmt == NULL)
-               return -EINVAL;
-
-       if (bih->frame_type == BEACON_FTYPE) {
-               mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
-                                                 IEEE80211_STYPE_BEACON);
-               memset(mgmt->da, 0xff, ETH_ALEN);
-       } else {
-               struct net_device *dev = vif->ndev;
-
-               mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
-                                                 IEEE80211_STYPE_PROBE_RESP);
-               memcpy(mgmt->da, dev->dev_addr, ETH_ALEN);
-       }
-       mgmt->duration = cpu_to_le16(0);
-       memcpy(mgmt->sa, bih->bssid, ETH_ALEN);
-       memcpy(mgmt->bssid, bih->bssid, ETH_ALEN);
-       mgmt->seq_ctrl = cpu_to_le16(0);
-
-       memcpy(&mgmt->u.beacon, buf, len);
-
-       bss = cfg80211_inform_bss_frame(ar->wiphy, channel, mgmt,
-                                       24 + len, (bih->snr - 95) * 100,
-                                       GFP_ATOMIC);
-       kfree(mgmt);
+       bss = cfg80211_inform_bss(ar->wiphy, channel,
+                                 bih->frame_type == BEACON_FTYPE ?
+                                       CFG80211_BSS_FTYPE_BEACON :
+                                       CFG80211_BSS_FTYPE_PRESP,
+                                 bih->bssid, get_unaligned_le64((__le64 *)buf),
+                                 get_unaligned_le16(((__le16 *)buf) + 5),
+                                 get_unaligned_le16(((__le16 *)buf) + 4),
+                                 buf + 8 + 2 + 2, len - 8 - 2 - 2,
+                                 (bih->snr - 95) * 100, GFP_ATOMIC);
        if (bss == NULL)
                return -ENOMEM;
        cfg80211_put_bss(ar->wiphy, bss);
index 8fcc029a76a60690ba542e49ddb94bb855bda3ba..b8f570ed39ad7ad2e48d4fdf13d16c67f5d0d8c6 100644 (file)
@@ -130,6 +130,15 @@ config ATH9K_RFKILL
          seconds. Turn off to save power, but enable it if you have
          a platform that can toggle the RF-Kill GPIO.
 
+config ATH9K_CHANNEL_CONTEXT
+       bool "Channel Context support"
+       depends on ATH9K
+       default n
+       ---help---
+         This option enables channel context support in ath9k, which is needed
+        for multi-channel concurrency. Enable this if P2P PowerSave support
+        is required.
+
 config ATH9K_HTC
        tristate "Atheros HTC based wireless cards support"
        depends on USB && MAC80211
index 7fc13a8da6757347e4daff1d1ede61da93648d3d..c690601f7276efe69e054fd1029e98b2f35fe1ba 100644 (file)
@@ -31,6 +31,7 @@
 #include "spectral.h"
 
 struct ath_node;
+struct ath_vif;
 
 extern struct ieee80211_ops ath9k_ops;
 extern int ath9k_modparam_nohwcrypt;
@@ -324,6 +325,10 @@ struct ath_rx {
        u32 ampdu_ref;
 };
 
+/*******************/
+/* Channel Context */
+/*******************/
+
 struct ath_chanctx {
        struct cfg80211_chan_def chandef;
        struct list_head vifs;
@@ -354,7 +359,9 @@ enum ath_chanctx_event {
        ATH_CHANCTX_EVENT_BEACON_RECEIVED,
        ATH_CHANCTX_EVENT_ASSOC,
        ATH_CHANCTX_EVENT_SWITCH,
+       ATH_CHANCTX_EVENT_ASSIGN,
        ATH_CHANCTX_EVENT_UNASSIGN,
+       ATH_CHANCTX_EVENT_CHANGE,
        ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL,
 };
 
@@ -403,35 +410,121 @@ struct ath_offchannel {
        int roc_duration;
        int duration;
 };
+
+#define case_rtn_string(val) case val: return #val
+
 #define ath_for_each_chanctx(_sc, _ctx)                             \
        for (ctx = &sc->chanctx[0];                                 \
             ctx <= &sc->chanctx[ARRAY_SIZE(sc->chanctx) - 1];      \
             ctx++)
 
-void ath9k_fill_chanctx_ops(void);
-void ath9k_chanctx_force_active(struct ieee80211_hw *hw,
-                               struct ieee80211_vif *vif);
+void ath_chanctx_init(struct ath_softc *sc);
+void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx,
+                            struct cfg80211_chan_def *chandef);
+
+#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
+
 static inline struct ath_chanctx *
 ath_chanctx_get(struct ieee80211_chanctx_conf *ctx)
 {
        struct ath_chanctx **ptr = (void *) ctx->drv_priv;
        return *ptr;
 }
-void ath_chanctx_init(struct ath_softc *sc);
-void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx,
-                            struct cfg80211_chan_def *chandef);
-void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx,
-                       struct cfg80211_chan_def *chandef);
+
+bool ath9k_is_chanctx_enabled(void);
+void ath9k_fill_chanctx_ops(void);
+void ath9k_init_channel_context(struct ath_softc *sc);
+void ath9k_offchannel_init(struct ath_softc *sc);
+void ath9k_deinit_channel_context(struct ath_softc *sc);
+int ath9k_init_p2p(struct ath_softc *sc);
+void ath9k_deinit_p2p(struct ath_softc *sc);
+void ath9k_p2p_remove_vif(struct ath_softc *sc,
+                         struct ieee80211_vif *vif);
+void ath9k_p2p_beacon_sync(struct ath_softc *sc);
+void ath9k_p2p_bss_info_changed(struct ath_softc *sc,
+                               struct ieee80211_vif *vif);
+void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp,
+                         struct sk_buff *skb);
+void ath9k_p2p_ps_timer(void *priv);
+void ath9k_chanctx_wake_queues(struct ath_softc *sc);
 void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx);
-void ath_offchannel_timer(unsigned long data);
-void ath_offchannel_channel_change(struct ath_softc *sc);
-void ath_chanctx_offchan_switch(struct ath_softc *sc,
-                               struct ieee80211_channel *chan);
-struct ath_chanctx *ath_chanctx_get_oper_chan(struct ath_softc *sc,
-                                             bool active);
+
+void ath_chanctx_beacon_recv_ev(struct ath_softc *sc, u32 ts,
+                               enum ath_chanctx_event ev);
+void ath_chanctx_beacon_sent_ev(struct ath_softc *sc,
+                               enum ath_chanctx_event ev);
 void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
                       enum ath_chanctx_event ev);
-void ath_chanctx_timer(unsigned long data);
+void ath_chanctx_set_next(struct ath_softc *sc, bool force);
+void ath_offchannel_next(struct ath_softc *sc);
+void ath_scan_complete(struct ath_softc *sc, bool abort);
+void ath_roc_complete(struct ath_softc *sc, bool abort);
+
+#else
+
+static inline bool ath9k_is_chanctx_enabled(void)
+{
+       return false;
+}
+static inline void ath9k_fill_chanctx_ops(void)
+{
+}
+static inline void ath9k_init_channel_context(struct ath_softc *sc)
+{
+}
+static inline void ath9k_offchannel_init(struct ath_softc *sc)
+{
+}
+static inline void ath9k_deinit_channel_context(struct ath_softc *sc)
+{
+}
+static inline void ath_chanctx_beacon_recv_ev(struct ath_softc *sc, u32 ts,
+                                             enum ath_chanctx_event ev)
+{
+}
+static inline void ath_chanctx_beacon_sent_ev(struct ath_softc *sc,
+                                             enum ath_chanctx_event ev)
+{
+}
+static inline void ath_chanctx_event(struct ath_softc *sc,
+                                    struct ieee80211_vif *vif,
+                                    enum ath_chanctx_event ev)
+{
+}
+static inline int ath9k_init_p2p(struct ath_softc *sc)
+{
+       return 0;
+}
+static inline void ath9k_deinit_p2p(struct ath_softc *sc)
+{
+}
+static inline void ath9k_p2p_remove_vif(struct ath_softc *sc,
+                                       struct ieee80211_vif *vif)
+{
+}
+static inline void ath9k_p2p_beacon_sync(struct ath_softc *sc)
+{
+}
+static inline void ath9k_p2p_bss_info_changed(struct ath_softc *sc,
+                                             struct ieee80211_vif *vif)
+{
+}
+static inline void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp,
+                                       struct sk_buff *skb)
+{
+}
+static inline void ath9k_p2p_ps_timer(struct ath_softc *sc)
+{
+}
+static inline void ath9k_chanctx_wake_queues(struct ath_softc *sc)
+{
+}
+static inline void ath_chanctx_check_active(struct ath_softc *sc,
+                                           struct ath_chanctx *ctx)
+{
+}
+
+#endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */
 
 int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan);
 int ath_startrecv(struct ath_softc *sc);
@@ -583,7 +676,6 @@ void ath9k_csa_update(struct ath_softc *sc);
 #define ATH_PAPRD_TIMEOUT         100 /* msecs */
 #define ATH_PLL_WORK_INTERVAL     100
 
-void ath_chanctx_work(struct work_struct *work);
 void ath_tx_complete_poll_work(struct work_struct *work);
 void ath_reset_work(struct work_struct *work);
 bool ath_hw_check(struct ath_softc *sc);
@@ -597,8 +689,6 @@ int ath_update_survey_stats(struct ath_softc *sc);
 void ath_update_survey_nf(struct ath_softc *sc, int channel);
 void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type);
 void ath_ps_full_sleep(unsigned long data);
-void ath9k_p2p_ps_timer(void *priv);
-void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif);
 void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop);
 
 /**********/
@@ -849,12 +939,17 @@ struct ath_softc {
        struct mutex mutex;
        struct work_struct paprd_work;
        struct work_struct hw_reset_work;
-       struct work_struct chanctx_work;
        struct completion paprd_complete;
        wait_queue_head_t tx_wait;
 
+#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
+       struct work_struct chanctx_work;
        struct ath_gen_timer *p2p_ps_timer;
        struct ath_vif *p2p_ps_vif;
+       struct ath_chanctx_sched sched;
+       struct ath_offchannel offchannel;
+       struct ath_chanctx *next_chan;
+#endif
 
        unsigned long driver_data;
 
@@ -875,10 +970,7 @@ struct ath_softc {
        struct cfg80211_chan_def cur_chandef;
        struct ath_chanctx chanctx[ATH9K_NUM_CHANCTX];
        struct ath_chanctx *cur_chan;
-       struct ath_chanctx *next_chan;
        spinlock_t chan_lock;
-       struct ath_offchannel offchannel;
-       struct ath_chanctx_sched sched;
 
 #ifdef CONFIG_MAC80211_LEDS
        bool led_registered;
index eaf8f058c15154941c1abfe0cc34585a5a217733..b2f56d8b9043783021c873a87cee6ed4772daf4d 100644 (file)
@@ -108,55 +108,6 @@ static void ath9k_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif,
        ath9k_hw_set_txdesc(ah, bf->bf_desc, &info);
 }
 
-static void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp,
-                                struct sk_buff *skb)
-{
-       static const u8 noa_ie_hdr[] = {
-               WLAN_EID_VENDOR_SPECIFIC,       /* type */
-               0,                              /* length */
-               0x50, 0x6f, 0x9a,               /* WFA OUI */
-               0x09,                           /* P2P subtype */
-               0x0c,                           /* Notice of Absence */
-               0x00,                           /* LSB of little-endian len */
-               0x00,                           /* MSB of little-endian len */
-       };
-
-       struct ieee80211_p2p_noa_attr *noa;
-       int noa_len, noa_desc, i = 0;
-       u8 *hdr;
-
-       if (!avp->offchannel_duration && !avp->periodic_noa_duration)
-               return;
-
-       noa_desc = !!avp->offchannel_duration + !!avp->periodic_noa_duration;
-       noa_len = 2 + sizeof(struct ieee80211_p2p_noa_desc) * noa_desc;
-
-       hdr = skb_put(skb, sizeof(noa_ie_hdr));
-       memcpy(hdr, noa_ie_hdr, sizeof(noa_ie_hdr));
-       hdr[1] = sizeof(noa_ie_hdr) + noa_len - 2;
-       hdr[7] = noa_len;
-
-       noa = (void *) skb_put(skb, noa_len);
-       memset(noa, 0, noa_len);
-
-       noa->index = avp->noa_index;
-       if (avp->periodic_noa_duration) {
-               u32 interval = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval);
-
-               noa->desc[i].count = 255;
-               noa->desc[i].start_time = cpu_to_le32(avp->periodic_noa_start);
-               noa->desc[i].duration = cpu_to_le32(avp->periodic_noa_duration);
-               noa->desc[i].interval = cpu_to_le32(interval);
-               i++;
-       }
-
-       if (avp->offchannel_duration) {
-               noa->desc[i].count = 1;
-               noa->desc[i].start_time = cpu_to_le32(avp->offchannel_start);
-               noa->desc[i].duration = cpu_to_le32(avp->offchannel_duration);
-       }
-}
-
 static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw,
                                             struct ieee80211_vif *vif)
 {
@@ -427,9 +378,10 @@ void ath9k_beacon_tasklet(unsigned long data)
 
        /* EDMA devices check that in the tx completion function. */
        if (!edma) {
-               if (sc->sched.beacon_pending)
-                       ath_chanctx_event(sc, NULL,
+               if (ath9k_is_chanctx_enabled()) {
+                       ath_chanctx_beacon_sent_ev(sc,
                                          ATH_CHANCTX_EVENT_BEACON_SENT);
+               }
 
                if (ath9k_csa_is_finished(sc, vif))
                        return;
@@ -438,7 +390,10 @@ void ath9k_beacon_tasklet(unsigned long data)
        if (!vif || !vif->bss_conf.enable_beacon)
                return;
 
-       ath_chanctx_event(sc, vif, ATH_CHANCTX_EVENT_BEACON_PREPARE);
+       if (ath9k_is_chanctx_enabled()) {
+               ath_chanctx_event(sc, vif, ATH_CHANCTX_EVENT_BEACON_PREPARE);
+       }
+
        bf = ath9k_beacon_generate(sc->hw, vif);
 
        if (sc->beacon.bmisscnt != 0) {
index ba214ebdcd167163cb38e50fb225b749d46005bf..409f912a67c7c2b760f90ce2c473fbd716566be3 100644 (file)
@@ -101,51 +101,100 @@ static int ath_set_channel(struct ath_softc *sc)
        return 0;
 }
 
-static bool
-ath_chanctx_send_vif_ps_frame(struct ath_softc *sc, struct ath_vif *avp,
-                             bool powersave)
+void ath_chanctx_init(struct ath_softc *sc)
 {
-       struct ieee80211_vif *vif = avp->vif;
-       struct ieee80211_sta *sta = NULL;
-       struct ieee80211_hdr_3addr *nullfunc;
-       struct ath_tx_control txctl;
-       struct sk_buff *skb;
-       int band = sc->cur_chan->chandef.chan->band;
+       struct ath_chanctx *ctx;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       struct ieee80211_supported_band *sband;
+       struct ieee80211_channel *chan;
+       int i, j;
 
-       switch (vif->type) {
-       case NL80211_IFTYPE_STATION:
-               if (!vif->bss_conf.assoc)
-                       return false;
+       sband = &common->sbands[IEEE80211_BAND_2GHZ];
+       if (!sband->n_channels)
+               sband = &common->sbands[IEEE80211_BAND_5GHZ];
 
-               skb = ieee80211_nullfunc_get(sc->hw, vif);
-               if (!skb)
-                       return false;
+       chan = &sband->channels[0];
+       for (i = 0; i < ATH9K_NUM_CHANCTX; i++) {
+               ctx = &sc->chanctx[i];
+               cfg80211_chandef_create(&ctx->chandef, chan, NL80211_CHAN_HT20);
+               INIT_LIST_HEAD(&ctx->vifs);
+               ctx->txpower = ATH_TXPOWER_MAX;
+               for (j = 0; j < ARRAY_SIZE(ctx->acq); j++)
+                       INIT_LIST_HEAD(&ctx->acq[j]);
+       }
+}
 
-               nullfunc = (struct ieee80211_hdr_3addr *) skb->data;
-               if (powersave)
-                       nullfunc->frame_control |=
-                               cpu_to_le16(IEEE80211_FCTL_PM);
+void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx,
+                            struct cfg80211_chan_def *chandef)
+{
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       bool cur_chan;
 
-               skb_set_queue_mapping(skb, IEEE80211_AC_VO);
-               if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, &sta)) {
-                       dev_kfree_skb_any(skb);
-                       return false;
-               }
-               break;
+       spin_lock_bh(&sc->chan_lock);
+       if (chandef)
+               memcpy(&ctx->chandef, chandef, sizeof(*chandef));
+       cur_chan = sc->cur_chan == ctx;
+       spin_unlock_bh(&sc->chan_lock);
+
+       if (!cur_chan) {
+               ath_dbg(common, CHAN_CTX,
+                       "Current context differs from the new context\n");
+               return;
+       }
+
+       ath_set_channel(sc);
+}
+
+#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
+
+/**********************************************************/
+/* Functions to handle the channel context state machine. */
+/**********************************************************/
+
+static const char *offchannel_state_string(enum ath_offchannel_state state)
+{
+       switch (state) {
+               case_rtn_string(ATH_OFFCHANNEL_IDLE);
+               case_rtn_string(ATH_OFFCHANNEL_PROBE_SEND);
+               case_rtn_string(ATH_OFFCHANNEL_PROBE_WAIT);
+               case_rtn_string(ATH_OFFCHANNEL_SUSPEND);
+               case_rtn_string(ATH_OFFCHANNEL_ROC_START);
+               case_rtn_string(ATH_OFFCHANNEL_ROC_WAIT);
+               case_rtn_string(ATH_OFFCHANNEL_ROC_DONE);
        default:
-               return false;
+               return "unknown";
        }
+}
 
-       memset(&txctl, 0, sizeof(txctl));
-       txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
-       txctl.sta = sta;
-       txctl.force_channel = true;
-       if (ath_tx_start(sc->hw, skb, &txctl)) {
-               ieee80211_free_txskb(sc->hw, skb);
-               return false;
+static const char *chanctx_event_string(enum ath_chanctx_event ev)
+{
+       switch (ev) {
+               case_rtn_string(ATH_CHANCTX_EVENT_BEACON_PREPARE);
+               case_rtn_string(ATH_CHANCTX_EVENT_BEACON_SENT);
+               case_rtn_string(ATH_CHANCTX_EVENT_TSF_TIMER);
+               case_rtn_string(ATH_CHANCTX_EVENT_BEACON_RECEIVED);
+               case_rtn_string(ATH_CHANCTX_EVENT_ASSOC);
+               case_rtn_string(ATH_CHANCTX_EVENT_SWITCH);
+               case_rtn_string(ATH_CHANCTX_EVENT_ASSIGN);
+               case_rtn_string(ATH_CHANCTX_EVENT_UNASSIGN);
+               case_rtn_string(ATH_CHANCTX_EVENT_CHANGE);
+               case_rtn_string(ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL);
+       default:
+               return "unknown";
        }
+}
 
-       return true;
+static const char *chanctx_state_string(enum ath_chanctx_state state)
+{
+       switch (state) {
+               case_rtn_string(ATH_CHANCTX_STATE_IDLE);
+               case_rtn_string(ATH_CHANCTX_STATE_WAIT_FOR_BEACON);
+               case_rtn_string(ATH_CHANCTX_STATE_WAIT_FOR_TIMER);
+               case_rtn_string(ATH_CHANCTX_STATE_SWITCH);
+               case_rtn_string(ATH_CHANCTX_STATE_FORCE_ACTIVE);
+       default:
+               return "unknown";
+       }
 }
 
 void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx)
@@ -186,354 +235,132 @@ void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx)
        }
        if (test_and_set_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
                return;
-       ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL);
-}
-
-static bool
-ath_chanctx_send_ps_frame(struct ath_softc *sc, bool powersave)
-{
-       struct ath_vif *avp;
-       bool sent = false;
 
-       rcu_read_lock();
-       list_for_each_entry(avp, &sc->cur_chan->vifs, list) {
-               if (ath_chanctx_send_vif_ps_frame(sc, avp, powersave))
-                       sent = true;
+       if (ath9k_is_chanctx_enabled()) {
+               ath_chanctx_event(sc, NULL,
+                                 ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL);
        }
-       rcu_read_unlock();
-
-       return sent;
 }
 
-static bool ath_chanctx_defer_switch(struct ath_softc *sc)
+static struct ath_chanctx *
+ath_chanctx_get_next(struct ath_softc *sc, struct ath_chanctx *ctx)
 {
-       if (sc->cur_chan == &sc->offchannel.chan)
-               return false;
-
-       switch (sc->sched.state) {
-       case ATH_CHANCTX_STATE_SWITCH:
-               return false;
-       case ATH_CHANCTX_STATE_IDLE:
-               if (!sc->cur_chan->switch_after_beacon)
-                       return false;
-
-               sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON;
-               break;
-       default:
-               break;
-       }
+       int idx = ctx - &sc->chanctx[0];
 
-       return true;
+       return &sc->chanctx[!idx];
 }
 
-static void ath_chanctx_set_next(struct ath_softc *sc, bool force)
+static void ath_chanctx_adjust_tbtt_delta(struct ath_softc *sc)
 {
+       struct ath_chanctx *prev, *cur;
        struct timespec ts;
-       bool measure_time = false;
-       bool send_ps = false;
-
-       spin_lock_bh(&sc->chan_lock);
-       if (!sc->next_chan) {
-               spin_unlock_bh(&sc->chan_lock);
-               return;
-       }
-
-       if (!force && ath_chanctx_defer_switch(sc)) {
-               spin_unlock_bh(&sc->chan_lock);
-               return;
-       }
-
-       if (sc->cur_chan != sc->next_chan) {
-               sc->cur_chan->stopped = true;
-               spin_unlock_bh(&sc->chan_lock);
-
-               if (sc->next_chan == &sc->offchannel.chan) {
-                       getrawmonotonic(&ts);
-                       measure_time = true;
-               }
-               __ath9k_flush(sc->hw, ~0, true);
+       u32 cur_tsf, prev_tsf, beacon_int;
+       s32 offset;
 
-               if (ath_chanctx_send_ps_frame(sc, true))
-                       __ath9k_flush(sc->hw, BIT(IEEE80211_AC_VO), false);
+       beacon_int = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval);
 
-               send_ps = true;
-               spin_lock_bh(&sc->chan_lock);
+       cur = sc->cur_chan;
+       prev = ath_chanctx_get_next(sc, cur);
 
-               if (sc->cur_chan != &sc->offchannel.chan) {
-                       getrawmonotonic(&sc->cur_chan->tsf_ts);
-                       sc->cur_chan->tsf_val = ath9k_hw_gettsf64(sc->sc_ah);
-               }
-       }
-       sc->cur_chan = sc->next_chan;
-       sc->cur_chan->stopped = false;
-       sc->next_chan = NULL;
-       sc->sched.offchannel_duration = 0;
-       if (sc->sched.state != ATH_CHANCTX_STATE_FORCE_ACTIVE)
-               sc->sched.state = ATH_CHANCTX_STATE_IDLE;
+       getrawmonotonic(&ts);
+       cur_tsf = (u32) cur->tsf_val +
+                 ath9k_hw_get_tsf_offset(&cur->tsf_ts, &ts);
 
-       spin_unlock_bh(&sc->chan_lock);
+       prev_tsf = prev->last_beacon - (u32) prev->tsf_val + cur_tsf;
+       prev_tsf -= ath9k_hw_get_tsf_offset(&prev->tsf_ts, &ts);
 
-       if (sc->sc_ah->chip_fullsleep ||
-           memcmp(&sc->cur_chandef, &sc->cur_chan->chandef,
-                  sizeof(sc->cur_chandef))) {
-               ath_set_channel(sc);
-               if (measure_time)
-                       sc->sched.channel_switch_time =
-                               ath9k_hw_get_tsf_offset(&ts, NULL);
-       }
-       if (send_ps)
-               ath_chanctx_send_ps_frame(sc, false);
+       /* Adjust the TSF time of the AP chanctx to keep its beacons
+        * at half beacon interval offset relative to the STA chanctx.
+        */
+       offset = cur_tsf - prev_tsf;
 
-       ath_offchannel_channel_change(sc);
-       ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_SWITCH);
-}
+       /* Ignore stale data or spurious timestamps */
+       if (offset < 0 || offset > 3 * beacon_int)
+               return;
 
-void ath_chanctx_work(struct work_struct *work)
-{
-       struct ath_softc *sc = container_of(work, struct ath_softc,
-                                           chanctx_work);
-       mutex_lock(&sc->mutex);
-       ath_chanctx_set_next(sc, false);
-       mutex_unlock(&sc->mutex);
+       offset = beacon_int / 2 - (offset % beacon_int);
+       prev->tsf_val += offset;
 }
 
-void ath_chanctx_init(struct ath_softc *sc)
+/* Configure the TSF based hardware timer for a channel switch.
+ * Also set up backup software timer, in case the gen timer fails.
+ * This could be caused by a hardware reset.
+ */
+static void ath_chanctx_setup_timer(struct ath_softc *sc, u32 tsf_time)
 {
-       struct ath_chanctx *ctx;
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-       struct ieee80211_supported_band *sband;
-       struct ieee80211_channel *chan;
-       int i, j;
-
-       sband = &common->sbands[IEEE80211_BAND_2GHZ];
-       if (!sband->n_channels)
-               sband = &common->sbands[IEEE80211_BAND_5GHZ];
+       struct ath_hw *ah = sc->sc_ah;
 
-       chan = &sband->channels[0];
-       for (i = 0; i < ATH9K_NUM_CHANCTX; i++) {
-               ctx = &sc->chanctx[i];
-               cfg80211_chandef_create(&ctx->chandef, chan, NL80211_CHAN_HT20);
-               INIT_LIST_HEAD(&ctx->vifs);
-               ctx->txpower = ATH_TXPOWER_MAX;
-               for (j = 0; j < ARRAY_SIZE(ctx->acq); j++)
-                       INIT_LIST_HEAD(&ctx->acq[j]);
-       }
-       ctx = &sc->offchannel.chan;
-       cfg80211_chandef_create(&ctx->chandef, chan, NL80211_CHAN_HT20);
-       INIT_LIST_HEAD(&ctx->vifs);
-       ctx->txpower = ATH_TXPOWER_MAX;
-       for (j = 0; j < ARRAY_SIZE(ctx->acq); j++)
-               INIT_LIST_HEAD(&ctx->acq[j]);
-       sc->offchannel.chan.offchannel = true;
+       ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, tsf_time, 1000000);
+       tsf_time -= ath9k_hw_gettsf32(ah);
+       tsf_time = msecs_to_jiffies(tsf_time / 1000) + 1;
+       mod_timer(&sc->sched.timer, jiffies + tsf_time);
 
+       ath_dbg(common, CHAN_CTX,
+               "Setup chanctx timer with timeout: %d ms\n", jiffies_to_msecs(tsf_time));
 }
 
-void ath9k_chanctx_force_active(struct ieee80211_hw *hw,
-                               struct ieee80211_vif *vif)
+void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
+                      enum ath_chanctx_event ev)
 {
-       struct ath_softc *sc = hw->priv;
-       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-       struct ath_vif *avp = (struct ath_vif *) vif->drv_priv;
-       bool changed = false;
-
-       if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
-               return;
-
-       if (!avp->chanctx)
-               return;
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath_beacon_config *cur_conf;
+       struct ath_vif *avp = NULL;
+       struct ath_chanctx *ctx;
+       u32 tsf_time;
+       u32 beacon_int;
+       bool noa_changed = false;
 
-       mutex_lock(&sc->mutex);
+       if (vif)
+               avp = (struct ath_vif *) vif->drv_priv;
 
        spin_lock_bh(&sc->chan_lock);
-       if (sc->next_chan || (sc->cur_chan != avp->chanctx)) {
-               sc->next_chan = avp->chanctx;
-               changed = true;
-       }
-       sc->sched.state = ATH_CHANCTX_STATE_FORCE_ACTIVE;
-       spin_unlock_bh(&sc->chan_lock);
 
-       if (changed)
-               ath_chanctx_set_next(sc, true);
+       ath_dbg(common, CHAN_CTX, "cur_chan: %d MHz, event: %s, state: %s\n",
+               sc->cur_chan->chandef.center_freq1,
+               chanctx_event_string(ev),
+               chanctx_state_string(sc->sched.state));
 
-       mutex_unlock(&sc->mutex);
-}
+       switch (ev) {
+       case ATH_CHANCTX_EVENT_BEACON_PREPARE:
+               if (avp->offchannel_duration)
+                       avp->offchannel_duration = 0;
 
-void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx,
-                       struct cfg80211_chan_def *chandef)
-{
-       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-
-       spin_lock_bh(&sc->chan_lock);
-
-       if (test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags) &&
-           (sc->cur_chan != ctx) && (ctx == &sc->offchannel.chan)) {
-               sc->sched.offchannel_pending = true;
-               spin_unlock_bh(&sc->chan_lock);
-               return;
-       }
-
-       sc->next_chan = ctx;
-       if (chandef)
-               ctx->chandef = *chandef;
-
-       if (sc->next_chan == &sc->offchannel.chan) {
-               sc->sched.offchannel_duration =
-                       TU_TO_USEC(sc->offchannel.duration) +
-                       sc->sched.channel_switch_time;
-       }
-       spin_unlock_bh(&sc->chan_lock);
-       ieee80211_queue_work(sc->hw, &sc->chanctx_work);
-}
-
-void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx,
-                            struct cfg80211_chan_def *chandef)
-{
-       bool cur_chan;
-
-       spin_lock_bh(&sc->chan_lock);
-       if (chandef)
-               memcpy(&ctx->chandef, chandef, sizeof(*chandef));
-       cur_chan = sc->cur_chan == ctx;
-       spin_unlock_bh(&sc->chan_lock);
-
-       if (!cur_chan)
-               return;
-
-       ath_set_channel(sc);
-}
-
-struct ath_chanctx *ath_chanctx_get_oper_chan(struct ath_softc *sc, bool active)
-{
-       struct ath_chanctx *ctx;
-
-       ath_for_each_chanctx(sc, ctx) {
-               if (!ctx->assigned || list_empty(&ctx->vifs))
-                       continue;
-               if (active && !ctx->active)
-                       continue;
-
-               if (ctx->switch_after_beacon)
-                       return ctx;
-       }
-
-       return &sc->chanctx[0];
-}
-
-void ath_chanctx_offchan_switch(struct ath_softc *sc,
-                               struct ieee80211_channel *chan)
-{
-       struct cfg80211_chan_def chandef;
-
-       cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT);
-
-       ath_chanctx_switch(sc, &sc->offchannel.chan, &chandef);
-}
-
-static struct ath_chanctx *
-ath_chanctx_get_next(struct ath_softc *sc, struct ath_chanctx *ctx)
-{
-       int idx = ctx - &sc->chanctx[0];
-
-       return &sc->chanctx[!idx];
-}
-
-static void ath_chanctx_adjust_tbtt_delta(struct ath_softc *sc)
-{
-       struct ath_chanctx *prev, *cur;
-       struct timespec ts;
-       u32 cur_tsf, prev_tsf, beacon_int;
-       s32 offset;
-
-       beacon_int = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval);
-
-       cur = sc->cur_chan;
-       prev = ath_chanctx_get_next(sc, cur);
-
-       getrawmonotonic(&ts);
-       cur_tsf = (u32) cur->tsf_val +
-                 ath9k_hw_get_tsf_offset(&cur->tsf_ts, &ts);
-
-       prev_tsf = prev->last_beacon - (u32) prev->tsf_val + cur_tsf;
-       prev_tsf -= ath9k_hw_get_tsf_offset(&prev->tsf_ts, &ts);
-
-       /* Adjust the TSF time of the AP chanctx to keep its beacons
-        * at half beacon interval offset relative to the STA chanctx.
-        */
-       offset = cur_tsf - prev_tsf;
-
-       /* Ignore stale data or spurious timestamps */
-       if (offset < 0 || offset > 3 * beacon_int)
-               return;
-
-       offset = beacon_int / 2 - (offset % beacon_int);
-       prev->tsf_val += offset;
-}
-
-void ath_chanctx_timer(unsigned long data)
-{
-       struct ath_softc *sc = (struct ath_softc *) data;
-
-       ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_TSF_TIMER);
-}
-
-/* Configure the TSF based hardware timer for a channel switch.
- * Also set up backup software timer, in case the gen timer fails.
- * This could be caused by a hardware reset.
- */
-static void ath_chanctx_setup_timer(struct ath_softc *sc, u32 tsf_time)
-{
-       struct ath_hw *ah = sc->sc_ah;
-
-       ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, tsf_time, 1000000);
-       tsf_time -= ath9k_hw_gettsf32(ah);
-       tsf_time = msecs_to_jiffies(tsf_time / 1000) + 1;
-       mod_timer(&sc->sched.timer, tsf_time);
-}
-
-void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
-                      enum ath_chanctx_event ev)
-{
-       struct ath_hw *ah = sc->sc_ah;
-       struct ath_common *common = ath9k_hw_common(ah);
-       struct ath_beacon_config *cur_conf;
-       struct ath_vif *avp = NULL;
-       struct ath_chanctx *ctx;
-       u32 tsf_time;
-       u32 beacon_int;
-       bool noa_changed = false;
-
-       if (vif)
-               avp = (struct ath_vif *) vif->drv_priv;
-
-       spin_lock_bh(&sc->chan_lock);
-
-       switch (ev) {
-       case ATH_CHANCTX_EVENT_BEACON_PREPARE:
-               if (avp->offchannel_duration)
-                       avp->offchannel_duration = 0;
-
-               if (avp->chanctx != sc->cur_chan)
+               if (avp->chanctx != sc->cur_chan) {
+                       ath_dbg(common, CHAN_CTX,
+                               "Contexts differ, not preparing beacon\n");
                        break;
+               }
 
                if (sc->sched.offchannel_pending) {
                        sc->sched.offchannel_pending = false;
                        sc->next_chan = &sc->offchannel.chan;
                        sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON;
+                       ath_dbg(common, CHAN_CTX,
+                               "Setting offchannel_pending to false\n");
                }
 
                ctx = ath_chanctx_get_next(sc, sc->cur_chan);
                if (ctx->active && sc->sched.state == ATH_CHANCTX_STATE_IDLE) {
                        sc->next_chan = ctx;
                        sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON;
+                       ath_dbg(common, CHAN_CTX,
+                               "Set next context, move chanctx state to WAIT_FOR_BEACON\n");
                }
 
                /* if the timer missed its window, use the next interval */
-               if (sc->sched.state == ATH_CHANCTX_STATE_WAIT_FOR_TIMER)
+               if (sc->sched.state == ATH_CHANCTX_STATE_WAIT_FOR_TIMER) {
                        sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON;
+                       ath_dbg(common, CHAN_CTX,
+                               "Move chanctx state from WAIT_FOR_TIMER to WAIT_FOR_BEACON\n");
+               }
 
                if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON)
                        break;
 
+               ath_dbg(common, CHAN_CTX, "Preparing beacon for vif: %pM\n", vif->addr);
+
                sc->sched.beacon_pending = true;
                sc->sched.next_tbtt = REG_READ(ah, AR_NEXT_TBTT_TIMER);
 
@@ -577,15 +404,28 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
 
                if (noa_changed)
                        avp->noa_index++;
+
+               ath_dbg(common, CHAN_CTX,
+                       "periodic_noa_duration: %d, periodic_noa_start: %d, noa_index: %d\n",
+                       avp->periodic_noa_duration,
+                       avp->periodic_noa_start,
+                       avp->noa_index);
+
                break;
        case ATH_CHANCTX_EVENT_BEACON_SENT:
-               if (!sc->sched.beacon_pending)
+               if (!sc->sched.beacon_pending) {
+                       ath_dbg(common, CHAN_CTX,
+                               "No pending beacon\n");
                        break;
+               }
 
                sc->sched.beacon_pending = false;
                if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON)
                        break;
 
+               ath_dbg(common, CHAN_CTX,
+                       "Move chanctx state to WAIT_FOR_TIMER\n");
+
                sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_TIMER;
                ath_chanctx_setup_timer(sc, sc->sched.switch_start_time);
                break;
@@ -597,6 +437,9 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
                    sc->sched.beacon_pending)
                        sc->sched.beacon_miss++;
 
+               ath_dbg(common, CHAN_CTX,
+                       "Move chanctx state to SWITCH\n");
+
                sc->sched.state = ATH_CHANCTX_STATE_SWITCH;
                ieee80211_queue_work(sc->hw, &sc->chanctx_work);
                break;
@@ -625,6 +468,9 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
                    avp->chanctx != sc->cur_chan)
                        break;
 
+               ath_dbg(common, CHAN_CTX,
+                       "Move chanctx state from FORCE_ACTIVE to IDLE\n");
+
                sc->sched.state = ATH_CHANCTX_STATE_IDLE;
                /* fall through */
        case ATH_CHANCTX_EVENT_SWITCH:
@@ -640,6 +486,9 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
                sc->next_chan = ath_chanctx_get_next(sc, sc->cur_chan);
                cur_conf = &sc->cur_chan->beacon;
 
+               ath_dbg(common, CHAN_CTX,
+                       "Move chanctx state to WAIT_FOR_TIMER (event SWITCH)\n");
+
                sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_TIMER;
 
                tsf_time = TU_TO_USEC(cur_conf->beacon_interval) / 2;
@@ -679,7 +528,785 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
                sc->next_chan = ctx;
                ieee80211_queue_work(sc->hw, &sc->chanctx_work);
                break;
+       case ATH_CHANCTX_EVENT_ASSIGN:
+               /*
+                * When adding a new channel context, check if a scan
+                * is in progress and abort it since the addition of
+                * a new channel context is usually followed by VIF
+                * assignment, in which case we have to start multi-channel
+                * operation.
+                */
+               if (test_bit(ATH_OP_SCANNING, &common->op_flags)) {
+                       ath_dbg(common, CHAN_CTX,
+                               "Aborting HW scan to add new context\n");
+
+                       spin_unlock_bh(&sc->chan_lock);
+                       del_timer_sync(&sc->offchannel.timer);
+                       ath_scan_complete(sc, true);
+                       spin_lock_bh(&sc->chan_lock);
+               }
+               break;
+       case ATH_CHANCTX_EVENT_CHANGE:
+               break;
+       }
+
+       spin_unlock_bh(&sc->chan_lock);
+}
+
+void ath_chanctx_beacon_sent_ev(struct ath_softc *sc,
+                               enum ath_chanctx_event ev)
+{
+       if (sc->sched.beacon_pending)
+               ath_chanctx_event(sc, NULL, ev);
+}
+
+void ath_chanctx_beacon_recv_ev(struct ath_softc *sc, u32 ts,
+                               enum ath_chanctx_event ev)
+{
+       sc->sched.next_tbtt = ts;
+       ath_chanctx_event(sc, NULL, ev);
+}
+
+static int ath_scan_channel_duration(struct ath_softc *sc,
+                                    struct ieee80211_channel *chan)
+{
+       struct cfg80211_scan_request *req = sc->offchannel.scan_req;
+
+       if (!req->n_ssids || (chan->flags & IEEE80211_CHAN_NO_IR))
+               return (HZ / 9); /* ~110 ms */
+
+       return (HZ / 16); /* ~60 ms */
+}
+
+static void ath_chanctx_switch(struct ath_softc *sc, struct ath_chanctx *ctx,
+                              struct cfg80211_chan_def *chandef)
+{
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+       spin_lock_bh(&sc->chan_lock);
+
+       if (test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags) &&
+           (sc->cur_chan != ctx) && (ctx == &sc->offchannel.chan)) {
+               sc->sched.offchannel_pending = true;
+               spin_unlock_bh(&sc->chan_lock);
+               return;
+       }
+
+       sc->next_chan = ctx;
+       if (chandef) {
+               ctx->chandef = *chandef;
+               ath_dbg(common, CHAN_CTX,
+                       "Assigned next_chan to %d MHz\n", chandef->center_freq1);
        }
 
+       if (sc->next_chan == &sc->offchannel.chan) {
+               sc->sched.offchannel_duration =
+                       TU_TO_USEC(sc->offchannel.duration) +
+                       sc->sched.channel_switch_time;
+
+               if (chandef) {
+                       ath_dbg(common, CHAN_CTX,
+                               "Offchannel duration for chan %d MHz : %u\n",
+                               chandef->center_freq1,
+                               sc->sched.offchannel_duration);
+               }
+       }
        spin_unlock_bh(&sc->chan_lock);
+       ieee80211_queue_work(sc->hw, &sc->chanctx_work);
+}
+
+static void ath_chanctx_offchan_switch(struct ath_softc *sc,
+                                      struct ieee80211_channel *chan)
+{
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       struct cfg80211_chan_def chandef;
+
+       cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT);
+       ath_dbg(common, CHAN_CTX,
+               "Channel definition created: %d MHz\n", chandef.center_freq1);
+
+       ath_chanctx_switch(sc, &sc->offchannel.chan, &chandef);
+}
+
+static struct ath_chanctx *ath_chanctx_get_oper_chan(struct ath_softc *sc,
+                                                    bool active)
+{
+       struct ath_chanctx *ctx;
+
+       ath_for_each_chanctx(sc, ctx) {
+               if (!ctx->assigned || list_empty(&ctx->vifs))
+                       continue;
+               if (active && !ctx->active)
+                       continue;
+
+               if (ctx->switch_after_beacon)
+                       return ctx;
+       }
+
+       return &sc->chanctx[0];
+}
+
+static void
+ath_scan_next_channel(struct ath_softc *sc)
+{
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       struct cfg80211_scan_request *req = sc->offchannel.scan_req;
+       struct ieee80211_channel *chan;
+
+       if (sc->offchannel.scan_idx >= req->n_channels) {
+               ath_dbg(common, CHAN_CTX,
+                       "Moving offchannel state to ATH_OFFCHANNEL_IDLE, "
+                       "scan_idx: %d, n_channels: %d\n",
+                       sc->offchannel.scan_idx,
+                       req->n_channels);
+
+               sc->offchannel.state = ATH_OFFCHANNEL_IDLE;
+               ath_chanctx_switch(sc, ath_chanctx_get_oper_chan(sc, false),
+                                  NULL);
+               return;
+       }
+
+       ath_dbg(common, CHAN_CTX,
+               "Moving offchannel state to ATH_OFFCHANNEL_PROBE_SEND, scan_idx: %d\n",
+               sc->offchannel.scan_idx);
+
+       chan = req->channels[sc->offchannel.scan_idx++];
+       sc->offchannel.duration = ath_scan_channel_duration(sc, chan);
+       sc->offchannel.state = ATH_OFFCHANNEL_PROBE_SEND;
+
+       ath_chanctx_offchan_switch(sc, chan);
+}
+
+void ath_offchannel_next(struct ath_softc *sc)
+{
+       struct ieee80211_vif *vif;
+
+       if (sc->offchannel.scan_req) {
+               vif = sc->offchannel.scan_vif;
+               sc->offchannel.chan.txpower = vif->bss_conf.txpower;
+               ath_scan_next_channel(sc);
+       } else if (sc->offchannel.roc_vif) {
+               vif = sc->offchannel.roc_vif;
+               sc->offchannel.chan.txpower = vif->bss_conf.txpower;
+               sc->offchannel.duration = sc->offchannel.roc_duration;
+               sc->offchannel.state = ATH_OFFCHANNEL_ROC_START;
+               ath_chanctx_offchan_switch(sc, sc->offchannel.roc_chan);
+       } else {
+               ath_chanctx_switch(sc, ath_chanctx_get_oper_chan(sc, false),
+                                  NULL);
+               sc->offchannel.state = ATH_OFFCHANNEL_IDLE;
+               if (sc->ps_idle)
+                       ath_cancel_work(sc);
+       }
+}
+
+void ath_roc_complete(struct ath_softc *sc, bool abort)
+{
+       sc->offchannel.roc_vif = NULL;
+       sc->offchannel.roc_chan = NULL;
+       if (!abort)
+               ieee80211_remain_on_channel_expired(sc->hw);
+       ath_offchannel_next(sc);
+       ath9k_ps_restore(sc);
+}
+
+void ath_scan_complete(struct ath_softc *sc, bool abort)
+{
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+       if (abort)
+               ath_dbg(common, CHAN_CTX, "HW scan aborted\n");
+       else
+               ath_dbg(common, CHAN_CTX, "HW scan complete\n");
+
+       sc->offchannel.scan_req = NULL;
+       sc->offchannel.scan_vif = NULL;
+       sc->offchannel.state = ATH_OFFCHANNEL_IDLE;
+       ieee80211_scan_completed(sc->hw, abort);
+       clear_bit(ATH_OP_SCANNING, &common->op_flags);
+       ath_offchannel_next(sc);
+       ath9k_ps_restore(sc);
 }
+
+static void ath_scan_send_probe(struct ath_softc *sc,
+                               struct cfg80211_ssid *ssid)
+{
+       struct cfg80211_scan_request *req = sc->offchannel.scan_req;
+       struct ieee80211_vif *vif = sc->offchannel.scan_vif;
+       struct ath_tx_control txctl = {};
+       struct sk_buff *skb;
+       struct ieee80211_tx_info *info;
+       int band = sc->offchannel.chan.chandef.chan->band;
+
+       skb = ieee80211_probereq_get(sc->hw, vif,
+                       ssid->ssid, ssid->ssid_len, req->ie_len);
+       if (!skb)
+               return;
+
+       info = IEEE80211_SKB_CB(skb);
+       if (req->no_cck)
+               info->flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
+
+       if (req->ie_len)
+               memcpy(skb_put(skb, req->ie_len), req->ie, req->ie_len);
+
+       skb_set_queue_mapping(skb, IEEE80211_AC_VO);
+
+       if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, NULL))
+               goto error;
+
+       txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
+       txctl.force_channel = true;
+       if (ath_tx_start(sc->hw, skb, &txctl))
+               goto error;
+
+       return;
+
+error:
+       ieee80211_free_txskb(sc->hw, skb);
+}
+
+static void ath_scan_channel_start(struct ath_softc *sc)
+{
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       struct cfg80211_scan_request *req = sc->offchannel.scan_req;
+       int i;
+
+       if (!(sc->cur_chan->chandef.chan->flags & IEEE80211_CHAN_NO_IR) &&
+           req->n_ssids) {
+               for (i = 0; i < req->n_ssids; i++)
+                       ath_scan_send_probe(sc, &req->ssids[i]);
+
+       }
+
+       ath_dbg(common, CHAN_CTX,
+               "Moving offchannel state to ATH_OFFCHANNEL_PROBE_WAIT\n");
+
+       sc->offchannel.state = ATH_OFFCHANNEL_PROBE_WAIT;
+       mod_timer(&sc->offchannel.timer, jiffies + sc->offchannel.duration);
+}
+
+static void ath_chanctx_timer(unsigned long data)
+{
+       struct ath_softc *sc = (struct ath_softc *) data;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+       ath_dbg(common, CHAN_CTX,
+               "Channel context timer invoked\n");
+
+       ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_TSF_TIMER);
+}
+
+static void ath_offchannel_timer(unsigned long data)
+{
+       struct ath_softc *sc = (struct ath_softc *)data;
+       struct ath_chanctx *ctx;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+       ath_dbg(common, CHAN_CTX, "%s: offchannel state: %s\n",
+               __func__, offchannel_state_string(sc->offchannel.state));
+
+       switch (sc->offchannel.state) {
+       case ATH_OFFCHANNEL_PROBE_WAIT:
+               if (!sc->offchannel.scan_req)
+                       return;
+
+               /* get first active channel context */
+               ctx = ath_chanctx_get_oper_chan(sc, true);
+               if (ctx->active) {
+                       ath_dbg(common, CHAN_CTX,
+                               "Switch to oper/active context, "
+                               "move offchannel state to ATH_OFFCHANNEL_SUSPEND\n");
+
+                       sc->offchannel.state = ATH_OFFCHANNEL_SUSPEND;
+                       ath_chanctx_switch(sc, ctx, NULL);
+                       mod_timer(&sc->offchannel.timer, jiffies + HZ / 10);
+                       break;
+               }
+               /* fall through */
+       case ATH_OFFCHANNEL_SUSPEND:
+               if (!sc->offchannel.scan_req)
+                       return;
+
+               ath_scan_next_channel(sc);
+               break;
+       case ATH_OFFCHANNEL_ROC_START:
+       case ATH_OFFCHANNEL_ROC_WAIT:
+               ctx = ath_chanctx_get_oper_chan(sc, false);
+               sc->offchannel.state = ATH_OFFCHANNEL_ROC_DONE;
+               ath_chanctx_switch(sc, ctx, NULL);
+               break;
+       default:
+               break;
+       }
+}
+
+static bool
+ath_chanctx_send_vif_ps_frame(struct ath_softc *sc, struct ath_vif *avp,
+                             bool powersave)
+{
+       struct ieee80211_vif *vif = avp->vif;
+       struct ieee80211_sta *sta = NULL;
+       struct ieee80211_hdr_3addr *nullfunc;
+       struct ath_tx_control txctl;
+       struct sk_buff *skb;
+       int band = sc->cur_chan->chandef.chan->band;
+
+       switch (vif->type) {
+       case NL80211_IFTYPE_STATION:
+               if (!vif->bss_conf.assoc)
+                       return false;
+
+               skb = ieee80211_nullfunc_get(sc->hw, vif);
+               if (!skb)
+                       return false;
+
+               nullfunc = (struct ieee80211_hdr_3addr *) skb->data;
+               if (powersave)
+                       nullfunc->frame_control |=
+                               cpu_to_le16(IEEE80211_FCTL_PM);
+
+               skb_set_queue_mapping(skb, IEEE80211_AC_VO);
+               if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, &sta)) {
+                       dev_kfree_skb_any(skb);
+                       return false;
+               }
+               break;
+       default:
+               return false;
+       }
+
+       memset(&txctl, 0, sizeof(txctl));
+       txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
+       txctl.sta = sta;
+       txctl.force_channel = true;
+       if (ath_tx_start(sc->hw, skb, &txctl)) {
+               ieee80211_free_txskb(sc->hw, skb);
+               return false;
+       }
+
+       return true;
+}
+
+static bool
+ath_chanctx_send_ps_frame(struct ath_softc *sc, bool powersave)
+{
+       struct ath_vif *avp;
+       bool sent = false;
+
+       rcu_read_lock();
+       list_for_each_entry(avp, &sc->cur_chan->vifs, list) {
+               if (ath_chanctx_send_vif_ps_frame(sc, avp, powersave))
+                       sent = true;
+       }
+       rcu_read_unlock();
+
+       return sent;
+}
+
+static bool ath_chanctx_defer_switch(struct ath_softc *sc)
+{
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+       if (sc->cur_chan == &sc->offchannel.chan)
+               return false;
+
+       switch (sc->sched.state) {
+       case ATH_CHANCTX_STATE_SWITCH:
+               return false;
+       case ATH_CHANCTX_STATE_IDLE:
+               if (!sc->cur_chan->switch_after_beacon)
+                       return false;
+
+               ath_dbg(common, CHAN_CTX,
+                       "Defer switch, set chanctx state to WAIT_FOR_BEACON\n");
+
+               sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON;
+               break;
+       default:
+               break;
+       }
+
+       return true;
+}
+
+static void ath_offchannel_channel_change(struct ath_softc *sc)
+{
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+       ath_dbg(common, CHAN_CTX, "%s: offchannel state: %s\n",
+               __func__, offchannel_state_string(sc->offchannel.state));
+
+       switch (sc->offchannel.state) {
+       case ATH_OFFCHANNEL_PROBE_SEND:
+               if (!sc->offchannel.scan_req)
+                       return;
+
+               if (sc->cur_chan->chandef.chan !=
+                   sc->offchannel.chan.chandef.chan)
+                       return;
+
+               ath_scan_channel_start(sc);
+               break;
+       case ATH_OFFCHANNEL_IDLE:
+               if (!sc->offchannel.scan_req)
+                       return;
+
+               ath_scan_complete(sc, false);
+               break;
+       case ATH_OFFCHANNEL_ROC_START:
+               if (sc->cur_chan != &sc->offchannel.chan)
+                       break;
+
+               sc->offchannel.state = ATH_OFFCHANNEL_ROC_WAIT;
+               mod_timer(&sc->offchannel.timer, jiffies +
+                         msecs_to_jiffies(sc->offchannel.duration));
+               ieee80211_ready_on_channel(sc->hw);
+               break;
+       case ATH_OFFCHANNEL_ROC_DONE:
+               ath_roc_complete(sc, false);
+               break;
+       default:
+               break;
+       }
+}
+
+void ath_chanctx_set_next(struct ath_softc *sc, bool force)
+{
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       struct timespec ts;
+       bool measure_time = false;
+       bool send_ps = false;
+
+       spin_lock_bh(&sc->chan_lock);
+       if (!sc->next_chan) {
+               spin_unlock_bh(&sc->chan_lock);
+               return;
+       }
+
+       if (!force && ath_chanctx_defer_switch(sc)) {
+               spin_unlock_bh(&sc->chan_lock);
+               return;
+       }
+
+       ath_dbg(common, CHAN_CTX,
+               "%s: current: %d MHz, next: %d MHz\n",
+               __func__,
+               sc->cur_chan->chandef.center_freq1,
+               sc->next_chan->chandef.center_freq1);
+
+       if (sc->cur_chan != sc->next_chan) {
+               ath_dbg(common, CHAN_CTX,
+                       "Stopping current chanctx: %d\n",
+                       sc->cur_chan->chandef.center_freq1);
+               sc->cur_chan->stopped = true;
+               spin_unlock_bh(&sc->chan_lock);
+
+               if (sc->next_chan == &sc->offchannel.chan) {
+                       getrawmonotonic(&ts);
+                       measure_time = true;
+               }
+               __ath9k_flush(sc->hw, ~0, true);
+
+               if (ath_chanctx_send_ps_frame(sc, true))
+                       __ath9k_flush(sc->hw, BIT(IEEE80211_AC_VO), false);
+
+               send_ps = true;
+               spin_lock_bh(&sc->chan_lock);
+
+               if (sc->cur_chan != &sc->offchannel.chan) {
+                       getrawmonotonic(&sc->cur_chan->tsf_ts);
+                       sc->cur_chan->tsf_val = ath9k_hw_gettsf64(sc->sc_ah);
+               }
+       }
+       sc->cur_chan = sc->next_chan;
+       sc->cur_chan->stopped = false;
+       sc->next_chan = NULL;
+       sc->sched.offchannel_duration = 0;
+       if (sc->sched.state != ATH_CHANCTX_STATE_FORCE_ACTIVE)
+               sc->sched.state = ATH_CHANCTX_STATE_IDLE;
+
+       spin_unlock_bh(&sc->chan_lock);
+
+       if (sc->sc_ah->chip_fullsleep ||
+           memcmp(&sc->cur_chandef, &sc->cur_chan->chandef,
+                  sizeof(sc->cur_chandef))) {
+               ath_dbg(common, CHAN_CTX,
+                       "%s: Set channel %d MHz\n",
+                       __func__, sc->cur_chan->chandef.center_freq1);
+               ath_set_channel(sc);
+               if (measure_time)
+                       sc->sched.channel_switch_time =
+                               ath9k_hw_get_tsf_offset(&ts, NULL);
+       }
+       if (send_ps)
+               ath_chanctx_send_ps_frame(sc, false);
+
+       ath_offchannel_channel_change(sc);
+       ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_SWITCH);
+}
+
+static void ath_chanctx_work(struct work_struct *work)
+{
+       struct ath_softc *sc = container_of(work, struct ath_softc,
+                                           chanctx_work);
+       mutex_lock(&sc->mutex);
+       ath_chanctx_set_next(sc, false);
+       mutex_unlock(&sc->mutex);
+}
+
+void ath9k_offchannel_init(struct ath_softc *sc)
+{
+       struct ath_chanctx *ctx;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       struct ieee80211_supported_band *sband;
+       struct ieee80211_channel *chan;
+       int i;
+
+       sband = &common->sbands[IEEE80211_BAND_2GHZ];
+       if (!sband->n_channels)
+               sband = &common->sbands[IEEE80211_BAND_5GHZ];
+
+       chan = &sband->channels[0];
+
+       ctx = &sc->offchannel.chan;
+       INIT_LIST_HEAD(&ctx->vifs);
+       ctx->txpower = ATH_TXPOWER_MAX;
+       cfg80211_chandef_create(&ctx->chandef, chan, NL80211_CHAN_HT20);
+
+       for (i = 0; i < ARRAY_SIZE(ctx->acq); i++)
+               INIT_LIST_HEAD(&ctx->acq[i]);
+
+       sc->offchannel.chan.offchannel = true;
+}
+
+void ath9k_init_channel_context(struct ath_softc *sc)
+{
+       INIT_WORK(&sc->chanctx_work, ath_chanctx_work);
+
+       setup_timer(&sc->offchannel.timer, ath_offchannel_timer,
+                   (unsigned long)sc);
+       setup_timer(&sc->sched.timer, ath_chanctx_timer,
+                   (unsigned long)sc);
+}
+
+void ath9k_deinit_channel_context(struct ath_softc *sc)
+{
+       cancel_work_sync(&sc->chanctx_work);
+}
+
+bool ath9k_is_chanctx_enabled(void)
+{
+       return (ath9k_use_chanctx == 1);
+}
+
+/********************/
+/* Queue management */
+/********************/
+
+void ath9k_chanctx_wake_queues(struct ath_softc *sc)
+{
+       struct ath_hw *ah = sc->sc_ah;
+       int i;
+
+       if (sc->cur_chan == &sc->offchannel.chan) {
+               ieee80211_wake_queue(sc->hw,
+                                    sc->hw->offchannel_tx_hw_queue);
+       } else {
+               for (i = 0; i < IEEE80211_NUM_ACS; i++)
+                       ieee80211_wake_queue(sc->hw,
+                                            sc->cur_chan->hw_queue_base + i);
+       }
+
+       if (ah->opmode == NL80211_IFTYPE_AP)
+               ieee80211_wake_queue(sc->hw, sc->hw->queues - 2);
+}
+
+/*****************/
+/* P2P Powersave */
+/*****************/
+
+static void ath9k_update_p2p_ps_timer(struct ath_softc *sc, struct ath_vif *avp)
+{
+       struct ath_hw *ah = sc->sc_ah;
+       s32 tsf, target_tsf;
+
+       if (!avp || !avp->noa.has_next_tsf)
+               return;
+
+       ath9k_hw_gen_timer_stop(ah, sc->p2p_ps_timer);
+
+       tsf = ath9k_hw_gettsf32(sc->sc_ah);
+
+       target_tsf = avp->noa.next_tsf;
+       if (!avp->noa.absent)
+               target_tsf -= ATH_P2P_PS_STOP_TIME;
+
+       if (target_tsf - tsf < ATH_P2P_PS_STOP_TIME)
+               target_tsf = tsf + ATH_P2P_PS_STOP_TIME;
+
+       ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, (u32) target_tsf, 1000000);
+}
+
+static void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif)
+{
+       struct ath_vif *avp = (void *)vif->drv_priv;
+       u32 tsf;
+
+       if (!sc->p2p_ps_timer)
+               return;
+
+       if (vif->type != NL80211_IFTYPE_STATION || !vif->p2p)
+               return;
+
+       sc->p2p_ps_vif = avp;
+       tsf = ath9k_hw_gettsf32(sc->sc_ah);
+       ieee80211_parse_p2p_noa(&vif->bss_conf.p2p_noa_attr, &avp->noa, tsf);
+       ath9k_update_p2p_ps_timer(sc, avp);
+}
+
+void ath9k_beacon_add_noa(struct ath_softc *sc, struct ath_vif *avp,
+                         struct sk_buff *skb)
+{
+       static const u8 noa_ie_hdr[] = {
+               WLAN_EID_VENDOR_SPECIFIC,       /* type */
+               0,                              /* length */
+               0x50, 0x6f, 0x9a,               /* WFA OUI */
+               0x09,                           /* P2P subtype */
+               0x0c,                           /* Notice of Absence */
+               0x00,                           /* LSB of little-endian len */
+               0x00,                           /* MSB of little-endian len */
+       };
+
+       struct ieee80211_p2p_noa_attr *noa;
+       int noa_len, noa_desc, i = 0;
+       u8 *hdr;
+
+       if (!avp->offchannel_duration && !avp->periodic_noa_duration)
+               return;
+
+       noa_desc = !!avp->offchannel_duration + !!avp->periodic_noa_duration;
+       noa_len = 2 + sizeof(struct ieee80211_p2p_noa_desc) * noa_desc;
+
+       hdr = skb_put(skb, sizeof(noa_ie_hdr));
+       memcpy(hdr, noa_ie_hdr, sizeof(noa_ie_hdr));
+       hdr[1] = sizeof(noa_ie_hdr) + noa_len - 2;
+       hdr[7] = noa_len;
+
+       noa = (void *) skb_put(skb, noa_len);
+       memset(noa, 0, noa_len);
+
+       noa->index = avp->noa_index;
+       if (avp->periodic_noa_duration) {
+               u32 interval = TU_TO_USEC(sc->cur_chan->beacon.beacon_interval);
+
+               noa->desc[i].count = 255;
+               noa->desc[i].start_time = cpu_to_le32(avp->periodic_noa_start);
+               noa->desc[i].duration = cpu_to_le32(avp->periodic_noa_duration);
+               noa->desc[i].interval = cpu_to_le32(interval);
+               i++;
+       }
+
+       if (avp->offchannel_duration) {
+               noa->desc[i].count = 1;
+               noa->desc[i].start_time = cpu_to_le32(avp->offchannel_start);
+               noa->desc[i].duration = cpu_to_le32(avp->offchannel_duration);
+       }
+}
+
+void ath9k_p2p_ps_timer(void *priv)
+{
+       struct ath_softc *sc = priv;
+       struct ath_vif *avp = sc->p2p_ps_vif;
+       struct ieee80211_vif *vif;
+       struct ieee80211_sta *sta;
+       struct ath_node *an;
+       u32 tsf;
+
+       del_timer_sync(&sc->sched.timer);
+       ath9k_hw_gen_timer_stop(sc->sc_ah, sc->p2p_ps_timer);
+       ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_TSF_TIMER);
+
+       if (!avp || avp->chanctx != sc->cur_chan)
+               return;
+
+       tsf = ath9k_hw_gettsf32(sc->sc_ah);
+       if (!avp->noa.absent)
+               tsf += ATH_P2P_PS_STOP_TIME;
+
+       if (!avp->noa.has_next_tsf ||
+           avp->noa.next_tsf - tsf > BIT(31))
+               ieee80211_update_p2p_noa(&avp->noa, tsf);
+
+       ath9k_update_p2p_ps_timer(sc, avp);
+
+       rcu_read_lock();
+
+       vif = avp->vif;
+       sta = ieee80211_find_sta(vif, vif->bss_conf.bssid);
+       if (!sta)
+               goto out;
+
+       an = (void *) sta->drv_priv;
+       if (an->sleeping == !!avp->noa.absent)
+               goto out;
+
+       an->sleeping = avp->noa.absent;
+       if (an->sleeping)
+               ath_tx_aggr_sleep(sta, sc, an);
+       else
+               ath_tx_aggr_wakeup(sc, an);
+
+out:
+       rcu_read_unlock();
+}
+
+void ath9k_p2p_bss_info_changed(struct ath_softc *sc,
+                               struct ieee80211_vif *vif)
+{
+       unsigned long flags;
+
+       spin_lock_bh(&sc->sc_pcu_lock);
+       spin_lock_irqsave(&sc->sc_pm_lock, flags);
+       if (!(sc->ps_flags & PS_BEACON_SYNC))
+               ath9k_update_p2p_ps(sc, vif);
+       spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+       spin_unlock_bh(&sc->sc_pcu_lock);
+}
+
+void ath9k_p2p_beacon_sync(struct ath_softc *sc)
+{
+       if (sc->p2p_ps_vif)
+               ath9k_update_p2p_ps(sc, sc->p2p_ps_vif->vif);
+}
+
+void ath9k_p2p_remove_vif(struct ath_softc *sc,
+                         struct ieee80211_vif *vif)
+{
+       struct ath_vif *avp = (void *)vif->drv_priv;
+
+       spin_lock_bh(&sc->sc_pcu_lock);
+       if (avp == sc->p2p_ps_vif) {
+               sc->p2p_ps_vif = NULL;
+               ath9k_update_p2p_ps_timer(sc, NULL);
+       }
+       spin_unlock_bh(&sc->sc_pcu_lock);
+}
+
+int ath9k_init_p2p(struct ath_softc *sc)
+{
+       sc->p2p_ps_timer = ath_gen_timer_alloc(sc->sc_ah, ath9k_p2p_ps_timer,
+                                              NULL, sc, AR_FIRST_NDP_TIMER);
+       if (!sc->p2p_ps_timer)
+               return -ENOMEM;
+
+       return 0;
+}
+
+void ath9k_deinit_p2p(struct ath_softc *sc)
+{
+       if (sc->p2p_ps_timer)
+               ath_gen_timer_free(sc->sc_ah, sc->p2p_ps_timer);
+}
+
+#endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */
index 8a3bd5fe3a548f9ac438691ea57a1f583f0291af..d779f4fa50e3a8392c697aaf0612bdea7ad99ad1 100644 (file)
@@ -592,6 +592,8 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
        hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN |
                            WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
 
+       hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
+
        hw->queues = 4;
        hw->max_listen_interval = 1;
 
index 39419ea845cc0640ea30927e600e5c2f769cf075..ca10a8b3a381405c0c059f4c0a2c3c38b8b5cf7e 100644 (file)
@@ -61,10 +61,14 @@ static int ath9k_ps_enable;
 module_param_named(ps_enable, ath9k_ps_enable, int, 0444);
 MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave");
 
+#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
+
 int ath9k_use_chanctx;
 module_param_named(use_chanctx, ath9k_use_chanctx, int, 0444);
 MODULE_PARM_DESC(use_chanctx, "Enable channel context for concurrency");
 
+#endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */
+
 bool is_ath9k_unloaded;
 
 #ifdef CONFIG_MAC80211_LEDS
@@ -511,7 +515,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
        sc->tx99_power = MAX_RATE_POWER + 1;
        init_waitqueue_head(&sc->tx_wait);
        sc->cur_chan = &sc->chanctx[0];
-       if (!ath9k_use_chanctx)
+       if (!ath9k_is_chanctx_enabled())
                sc->cur_chan->hw_queue_base = 0;
 
        if (!pdata || pdata->use_eeprom) {
@@ -567,11 +571,9 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
        setup_timer(&sc->sleep_timer, ath_ps_full_sleep, (unsigned long)sc);
        INIT_WORK(&sc->hw_reset_work, ath_reset_work);
        INIT_WORK(&sc->paprd_work, ath_paprd_calibrate);
-       INIT_WORK(&sc->chanctx_work, ath_chanctx_work);
        INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work);
-       setup_timer(&sc->offchannel.timer, ath_offchannel_timer,
-                   (unsigned long)sc);
-       setup_timer(&sc->sched.timer, ath_chanctx_timer, (unsigned long)sc);
+
+       ath9k_init_channel_context(sc);
 
        /*
         * Cache line size is used to size and align various
@@ -600,13 +602,15 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
        if (ret)
                goto err_btcoex;
 
-       sc->p2p_ps_timer = ath_gen_timer_alloc(sc->sc_ah, ath9k_p2p_ps_timer,
-               NULL, sc, AR_FIRST_NDP_TIMER);
+       ret = ath9k_init_p2p(sc);
+       if (ret)
+               goto err_btcoex;
 
        ath9k_cmn_init_crypto(sc->sc_ah);
        ath9k_init_misc(sc);
        ath_fill_led_pin(sc);
        ath_chanctx_init(sc);
+       ath9k_offchannel_init(sc);
 
        if (common->bus_ops->aspm_init)
                common->bus_ops->aspm_init(common);
@@ -672,18 +676,14 @@ static const struct ieee80211_iface_limit wds_limits[] = {
        { .max = 2048,  .types = BIT(NL80211_IFTYPE_WDS) },
 };
 
+#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
+
 static const struct ieee80211_iface_limit if_limits_multi[] = {
-       { .max = 1,     .types = BIT(NL80211_IFTYPE_STATION) },
-       { .max = 1,     .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
+       { .max = 2,     .types = BIT(NL80211_IFTYPE_STATION) |
+                                BIT(NL80211_IFTYPE_AP) |
+                                BIT(NL80211_IFTYPE_P2P_CLIENT) |
                                 BIT(NL80211_IFTYPE_P2P_GO) },
-};
-
-static const struct ieee80211_iface_limit if_dfs_limits[] = {
-       { .max = 1,     .types = BIT(NL80211_IFTYPE_AP) |
-#ifdef CONFIG_MAC80211_MESH
-                                BIT(NL80211_IFTYPE_MESH_POINT) |
-#endif
-                                BIT(NL80211_IFTYPE_ADHOC) },
+       { .max = 1,     .types = BIT(NL80211_IFTYPE_ADHOC) },
 };
 
 static const struct ieee80211_iface_combination if_comb_multi[] = {
@@ -696,6 +696,16 @@ static const struct ieee80211_iface_combination if_comb_multi[] = {
        },
 };
 
+#endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */
+
+static const struct ieee80211_iface_limit if_dfs_limits[] = {
+       { .max = 1,     .types = BIT(NL80211_IFTYPE_AP) |
+#ifdef CONFIG_MAC80211_MESH
+                                BIT(NL80211_IFTYPE_MESH_POINT) |
+#endif
+                                BIT(NL80211_IFTYPE_ADHOC) },
+};
+
 static const struct ieee80211_iface_combination if_comb[] = {
        {
                .limits = if_limits,
@@ -763,24 +773,31 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
                        BIT(NL80211_IFTYPE_AP) |
                        BIT(NL80211_IFTYPE_STATION) |
                        BIT(NL80211_IFTYPE_ADHOC) |
-                       BIT(NL80211_IFTYPE_MESH_POINT);
-               if (!ath9k_use_chanctx) {
+                       BIT(NL80211_IFTYPE_MESH_POINT) |
+                       BIT(NL80211_IFTYPE_WDS);
+
                        hw->wiphy->iface_combinations = if_comb;
                        hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
-                       hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_WDS);
-               } else {
-                       hw->wiphy->iface_combinations = if_comb_multi;
-                       hw->wiphy->n_iface_combinations =
-                               ARRAY_SIZE(if_comb_multi);
-                       hw->wiphy->max_scan_ssids = 255;
-                       hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
-                       hw->wiphy->max_remain_on_channel_duration = 10000;
-                       hw->chanctx_data_size = sizeof(void *);
-                       hw->extra_beacon_tailroom =
-                               sizeof(struct ieee80211_p2p_noa_attr) + 9;
-               }
        }
 
+#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
+
+       if (ath9k_is_chanctx_enabled()) {
+               hw->wiphy->interface_modes &= ~ BIT(NL80211_IFTYPE_WDS);
+               hw->wiphy->iface_combinations = if_comb_multi;
+               hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb_multi);
+               hw->wiphy->max_scan_ssids = 255;
+               hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
+               hw->wiphy->max_remain_on_channel_duration = 10000;
+               hw->chanctx_data_size = sizeof(void *);
+               hw->extra_beacon_tailroom =
+                       sizeof(struct ieee80211_p2p_noa_attr) + 9;
+
+               ath_dbg(common, CHAN_CTX, "Use channel contexts\n");
+       }
+
+#endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */
+
        hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
 
        hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
@@ -915,9 +932,7 @@ static void ath9k_deinit_softc(struct ath_softc *sc)
 {
        int i = 0;
 
-       if (sc->p2p_ps_timer)
-               ath_gen_timer_free(sc->sc_ah, sc->p2p_ps_timer);
-
+       ath9k_deinit_p2p(sc);
        ath9k_deinit_btcoex(sc);
 
        for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
index e6ac8d2e610ca421f60dbfa6eb68dd46f8061c9d..d9be83158a82bc740bd3a0a78a46b38bcdcdc24d 100644 (file)
@@ -223,7 +223,6 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start)
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
        unsigned long flags;
-       int i;
 
        if (ath_startrecv(sc) != 0) {
                ath_err(common, "Unable to restart recv logic\n");
@@ -268,20 +267,10 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start)
        ath9k_hw_set_interrupts(ah);
        ath9k_hw_enable_interrupts(ah);
 
-       if (!ath9k_use_chanctx)
+       if (!ath9k_is_chanctx_enabled())
                ieee80211_wake_queues(sc->hw);
-       else {
-               if (sc->cur_chan == &sc->offchannel.chan)
-                       ieee80211_wake_queue(sc->hw,
-                                       sc->hw->offchannel_tx_hw_queue);
-               else {
-                       for (i = 0; i < IEEE80211_NUM_ACS; i++)
-                               ieee80211_wake_queue(sc->hw,
-                                       sc->cur_chan->hw_queue_base + i);
-               }
-               if (ah->opmode == NL80211_IFTYPE_AP)
-                       ieee80211_wake_queue(sc->hw, sc->hw->queues - 2);
-       }
+       else
+               ath9k_chanctx_wake_queues(sc);
 
        ath9k_p2p_ps_timer(sc);
 
@@ -314,6 +303,9 @@ int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan)
        if (!ath_prepare_reset(sc))
                fastcc = false;
 
+       if (ath9k_is_chanctx_enabled())
+               fastcc = false;
+
        spin_lock_bh(&sc->chan_lock);
        sc->cur_chandef = sc->cur_chan->chandef;
        spin_unlock_bh(&sc->chan_lock);
@@ -822,7 +814,8 @@ static void ath9k_stop(struct ieee80211_hw *hw)
        struct ath_common *common = ath9k_hw_common(ah);
        bool prev_idle;
 
-       cancel_work_sync(&sc->chanctx_work);
+       ath9k_deinit_channel_context(sc);
+
        mutex_lock(&sc->mutex);
 
        ath_cancel_work(sc);
@@ -903,9 +896,9 @@ static bool ath9k_uses_beacons(int type)
        }
 }
 
-static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
+static void ath9k_vif_iter(struct ath9k_vif_iter_data *iter_data,
+                          u8 *mac, struct ieee80211_vif *vif)
 {
-       struct ath9k_vif_iter_data *iter_data = data;
        int i;
 
        if (iter_data->has_hw_macaddr) {
@@ -968,6 +961,7 @@ void ath9k_calculate_iter_data(struct ath_softc *sc,
        list_for_each_entry(avp, &ctx->vifs, list)
                ath9k_vif_iter(iter_data, avp->vif->addr, avp->vif);
 
+#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
        if (ctx == &sc->offchannel.chan) {
                struct ieee80211_vif *vif;
 
@@ -980,6 +974,7 @@ void ath9k_calculate_iter_data(struct ath_softc *sc,
                        ath9k_vif_iter(iter_data, vif->addr, vif);
                iter_data->beacons = false;
        }
+#endif
 }
 
 static void ath9k_set_assoc_state(struct ath_softc *sc,
@@ -1139,7 +1134,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
                ath9k_beacon_assign_slot(sc, vif);
 
        avp->vif = vif;
-       if (!ath9k_use_chanctx) {
+       if (!ath9k_is_chanctx_enabled()) {
                avp->chanctx = sc->cur_chan;
                list_add_tail(&avp->list, &avp->chanctx->vifs);
        }
@@ -1202,29 +1197,6 @@ static int ath9k_change_interface(struct ieee80211_hw *hw,
        return 0;
 }
 
-static void
-ath9k_update_p2p_ps_timer(struct ath_softc *sc, struct ath_vif *avp)
-{
-       struct ath_hw *ah = sc->sc_ah;
-       s32 tsf, target_tsf;
-
-       if (!avp || !avp->noa.has_next_tsf)
-               return;
-
-       ath9k_hw_gen_timer_stop(ah, sc->p2p_ps_timer);
-
-       tsf = ath9k_hw_gettsf32(sc->sc_ah);
-
-       target_tsf = avp->noa.next_tsf;
-       if (!avp->noa.absent)
-               target_tsf -= ATH_P2P_PS_STOP_TIME;
-
-       if (target_tsf - tsf < ATH_P2P_PS_STOP_TIME)
-               target_tsf = tsf + ATH_P2P_PS_STOP_TIME;
-
-       ath9k_hw_gen_timer_start(ah, sc->p2p_ps_timer, (u32) target_tsf, 1000000);
-}
-
 static void ath9k_remove_interface(struct ieee80211_hw *hw,
                                   struct ieee80211_vif *vif)
 {
@@ -1236,16 +1208,11 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
 
        mutex_lock(&sc->mutex);
 
-       spin_lock_bh(&sc->sc_pcu_lock);
-       if (avp == sc->p2p_ps_vif) {
-               sc->p2p_ps_vif = NULL;
-               ath9k_update_p2p_ps_timer(sc, NULL);
-       }
-       spin_unlock_bh(&sc->sc_pcu_lock);
+       ath9k_p2p_remove_vif(sc, vif);
 
        sc->nvifs--;
        sc->tx99_vif = NULL;
-       if (!ath9k_use_chanctx)
+       if (!ath9k_is_chanctx_enabled())
                list_del(&avp->list);
 
        if (ath9k_uses_beacons(vif->type))
@@ -1423,7 +1390,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
                }
        }
 
-       if (!ath9k_use_chanctx && (changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
+       if (!ath9k_is_chanctx_enabled() && (changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
                ctx->offchannel = !!(conf->flags & IEEE80211_CONF_OFFCHANNEL);
                ath_chanctx_set_channel(sc, ctx, &hw->conf.chandef);
        }
@@ -1687,70 +1654,6 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
        return ret;
 }
 
-void ath9k_p2p_ps_timer(void *priv)
-{
-       struct ath_softc *sc = priv;
-       struct ath_vif *avp = sc->p2p_ps_vif;
-       struct ieee80211_vif *vif;
-       struct ieee80211_sta *sta;
-       struct ath_node *an;
-       u32 tsf;
-
-       del_timer_sync(&sc->sched.timer);
-       ath9k_hw_gen_timer_stop(sc->sc_ah, sc->p2p_ps_timer);
-       ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_TSF_TIMER);
-
-       if (!avp || avp->chanctx != sc->cur_chan)
-               return;
-
-       tsf = ath9k_hw_gettsf32(sc->sc_ah);
-       if (!avp->noa.absent)
-               tsf += ATH_P2P_PS_STOP_TIME;
-
-       if (!avp->noa.has_next_tsf ||
-           avp->noa.next_tsf - tsf > BIT(31))
-               ieee80211_update_p2p_noa(&avp->noa, tsf);
-
-       ath9k_update_p2p_ps_timer(sc, avp);
-
-       rcu_read_lock();
-
-       vif = avp->vif;
-       sta = ieee80211_find_sta(vif, vif->bss_conf.bssid);
-       if (!sta)
-               goto out;
-
-       an = (void *) sta->drv_priv;
-       if (an->sleeping == !!avp->noa.absent)
-               goto out;
-
-       an->sleeping = avp->noa.absent;
-       if (an->sleeping)
-               ath_tx_aggr_sleep(sta, sc, an);
-       else
-               ath_tx_aggr_wakeup(sc, an);
-
-out:
-       rcu_read_unlock();
-}
-
-void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif)
-{
-       struct ath_vif *avp = (void *)vif->drv_priv;
-       u32 tsf;
-
-       if (!sc->p2p_ps_timer)
-               return;
-
-       if (vif->type != NL80211_IFTYPE_STATION || !vif->p2p)
-               return;
-
-       sc->p2p_ps_vif = avp;
-       tsf = ath9k_hw_gettsf32(sc->sc_ah);
-       ieee80211_parse_p2p_noa(&vif->bss_conf.p2p_noa_attr, &avp->noa, tsf);
-       ath9k_update_p2p_ps_timer(sc, avp);
-}
-
 static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
                                   struct ieee80211_vif *vif,
                                   struct ieee80211_bss_conf *bss_conf,
@@ -1765,7 +1668,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
        struct ath_vif *avp = (void *)vif->drv_priv;
-       unsigned long flags;
        int slottime;
 
        ath9k_ps_wakeup(sc);
@@ -1776,8 +1678,12 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
                        bss_conf->bssid, bss_conf->assoc);
 
                ath9k_calculate_summary_state(sc, avp->chanctx);
-               if (bss_conf->assoc)
-                       ath_chanctx_event(sc, vif, ATH_CHANCTX_EVENT_ASSOC);
+
+               if (ath9k_is_chanctx_enabled()) {
+                       if (bss_conf->assoc)
+                               ath_chanctx_event(sc, vif,
+                                                 ATH_CHANCTX_EVENT_ASSOC);
+               }
        }
 
        if (changed & BSS_CHANGED_IBSS) {
@@ -1814,14 +1720,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
                }
        }
 
-       if (changed & BSS_CHANGED_P2P_PS) {
-               spin_lock_bh(&sc->sc_pcu_lock);
-               spin_lock_irqsave(&sc->sc_pm_lock, flags);
-               if (!(sc->ps_flags & PS_BEACON_SYNC))
-                       ath9k_update_p2p_ps(sc, vif);
-               spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
-               spin_unlock_bh(&sc->sc_pcu_lock);
-       }
+       if (changed & BSS_CHANGED_P2P_PS)
+               ath9k_p2p_bss_info_changed(sc, vif);
 
        if (changed & CHECK_ANI)
                ath_check_ani(sc);
@@ -2207,207 +2107,7 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
        clear_bit(ATH_OP_SCANNING, &common->op_flags);
 }
 
-static int ath_scan_channel_duration(struct ath_softc *sc,
-                                    struct ieee80211_channel *chan)
-{
-       struct cfg80211_scan_request *req = sc->offchannel.scan_req;
-
-       if (!req->n_ssids || (chan->flags & IEEE80211_CHAN_NO_IR))
-               return (HZ / 9); /* ~110 ms */
-
-       return (HZ / 16); /* ~60 ms */
-}
-
-static void
-ath_scan_next_channel(struct ath_softc *sc)
-{
-       struct cfg80211_scan_request *req = sc->offchannel.scan_req;
-       struct ieee80211_channel *chan;
-
-       if (sc->offchannel.scan_idx >= req->n_channels) {
-               sc->offchannel.state = ATH_OFFCHANNEL_IDLE;
-               ath_chanctx_switch(sc, ath_chanctx_get_oper_chan(sc, false),
-                                  NULL);
-               return;
-       }
-
-       chan = req->channels[sc->offchannel.scan_idx++];
-       sc->offchannel.duration = ath_scan_channel_duration(sc, chan);
-       sc->offchannel.state = ATH_OFFCHANNEL_PROBE_SEND;
-       ath_chanctx_offchan_switch(sc, chan);
-}
-
-static void ath_offchannel_next(struct ath_softc *sc)
-{
-       struct ieee80211_vif *vif;
-
-       if (sc->offchannel.scan_req) {
-               vif = sc->offchannel.scan_vif;
-               sc->offchannel.chan.txpower = vif->bss_conf.txpower;
-               ath_scan_next_channel(sc);
-       } else if (sc->offchannel.roc_vif) {
-               vif = sc->offchannel.roc_vif;
-               sc->offchannel.chan.txpower = vif->bss_conf.txpower;
-               sc->offchannel.duration = sc->offchannel.roc_duration;
-               sc->offchannel.state = ATH_OFFCHANNEL_ROC_START;
-               ath_chanctx_offchan_switch(sc, sc->offchannel.roc_chan);
-       } else {
-               ath_chanctx_switch(sc, ath_chanctx_get_oper_chan(sc, false),
-                                  NULL);
-               sc->offchannel.state = ATH_OFFCHANNEL_IDLE;
-               if (sc->ps_idle)
-                       ath_cancel_work(sc);
-       }
-}
-
-static void ath_roc_complete(struct ath_softc *sc, bool abort)
-{
-       sc->offchannel.roc_vif = NULL;
-       sc->offchannel.roc_chan = NULL;
-       if (!abort)
-               ieee80211_remain_on_channel_expired(sc->hw);
-       ath_offchannel_next(sc);
-       ath9k_ps_restore(sc);
-}
-
-static void ath_scan_complete(struct ath_softc *sc, bool abort)
-{
-       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-
-       sc->offchannel.scan_req = NULL;
-       sc->offchannel.scan_vif = NULL;
-       sc->offchannel.state = ATH_OFFCHANNEL_IDLE;
-       ieee80211_scan_completed(sc->hw, abort);
-       clear_bit(ATH_OP_SCANNING, &common->op_flags);
-       ath_offchannel_next(sc);
-       ath9k_ps_restore(sc);
-}
-
-static void ath_scan_send_probe(struct ath_softc *sc,
-                               struct cfg80211_ssid *ssid)
-{
-       struct cfg80211_scan_request *req = sc->offchannel.scan_req;
-       struct ieee80211_vif *vif = sc->offchannel.scan_vif;
-       struct ath_tx_control txctl = {};
-       struct sk_buff *skb;
-       struct ieee80211_tx_info *info;
-       int band = sc->offchannel.chan.chandef.chan->band;
-
-       skb = ieee80211_probereq_get(sc->hw, vif,
-                       ssid->ssid, ssid->ssid_len, req->ie_len);
-       if (!skb)
-               return;
-
-       info = IEEE80211_SKB_CB(skb);
-       if (req->no_cck)
-               info->flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
-
-       if (req->ie_len)
-               memcpy(skb_put(skb, req->ie_len), req->ie, req->ie_len);
-
-       skb_set_queue_mapping(skb, IEEE80211_AC_VO);
-
-       if (!ieee80211_tx_prepare_skb(sc->hw, vif, skb, band, NULL))
-               goto error;
-
-       txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
-       txctl.force_channel = true;
-       if (ath_tx_start(sc->hw, skb, &txctl))
-               goto error;
-
-       return;
-
-error:
-       ieee80211_free_txskb(sc->hw, skb);
-}
-
-static void ath_scan_channel_start(struct ath_softc *sc)
-{
-       struct cfg80211_scan_request *req = sc->offchannel.scan_req;
-       int i;
-
-       if (!(sc->cur_chan->chandef.chan->flags & IEEE80211_CHAN_NO_IR) &&
-           req->n_ssids) {
-               for (i = 0; i < req->n_ssids; i++)
-                       ath_scan_send_probe(sc, &req->ssids[i]);
-
-       }
-
-       sc->offchannel.state = ATH_OFFCHANNEL_PROBE_WAIT;
-       mod_timer(&sc->offchannel.timer, jiffies + sc->offchannel.duration);
-}
-
-void ath_offchannel_channel_change(struct ath_softc *sc)
-{
-       switch (sc->offchannel.state) {
-       case ATH_OFFCHANNEL_PROBE_SEND:
-               if (!sc->offchannel.scan_req)
-                       return;
-
-               if (sc->cur_chan->chandef.chan !=
-                   sc->offchannel.chan.chandef.chan)
-                       return;
-
-               ath_scan_channel_start(sc);
-               break;
-       case ATH_OFFCHANNEL_IDLE:
-               if (!sc->offchannel.scan_req)
-                       return;
-
-               ath_scan_complete(sc, false);
-               break;
-       case ATH_OFFCHANNEL_ROC_START:
-               if (sc->cur_chan != &sc->offchannel.chan)
-                       break;
-
-               sc->offchannel.state = ATH_OFFCHANNEL_ROC_WAIT;
-               mod_timer(&sc->offchannel.timer, jiffies +
-                         msecs_to_jiffies(sc->offchannel.duration));
-               ieee80211_ready_on_channel(sc->hw);
-               break;
-       case ATH_OFFCHANNEL_ROC_DONE:
-               ath_roc_complete(sc, false);
-               break;
-       default:
-               break;
-       }
-}
-
-void ath_offchannel_timer(unsigned long data)
-{
-       struct ath_softc *sc = (struct ath_softc *)data;
-       struct ath_chanctx *ctx;
-
-       switch (sc->offchannel.state) {
-       case ATH_OFFCHANNEL_PROBE_WAIT:
-               if (!sc->offchannel.scan_req)
-                       return;
-
-               /* get first active channel context */
-               ctx = ath_chanctx_get_oper_chan(sc, true);
-               if (ctx->active) {
-                       sc->offchannel.state = ATH_OFFCHANNEL_SUSPEND;
-                       ath_chanctx_switch(sc, ctx, NULL);
-                       mod_timer(&sc->offchannel.timer, jiffies + HZ / 10);
-                       break;
-               }
-               /* fall through */
-       case ATH_OFFCHANNEL_SUSPEND:
-               if (!sc->offchannel.scan_req)
-                       return;
-
-               ath_scan_next_channel(sc);
-               break;
-       case ATH_OFFCHANNEL_ROC_START:
-       case ATH_OFFCHANNEL_ROC_WAIT:
-               ctx = ath_chanctx_get_oper_chan(sc, false);
-               sc->offchannel.state = ATH_OFFCHANNEL_ROC_DONE;
-               ath_chanctx_switch(sc, ctx, NULL);
-               break;
-       default:
-               break;
-       }
-}
+#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
 
 static int ath9k_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                         struct ieee80211_scan_request *hw_req)
@@ -2430,8 +2130,13 @@ static int ath9k_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
        sc->offchannel.scan_req = req;
        sc->offchannel.scan_idx = 0;
 
-       if (sc->offchannel.state == ATH_OFFCHANNEL_IDLE)
+       ath_dbg(common, CHAN_CTX, "HW scan request received on vif: %pM\n",
+               vif->addr);
+
+       if (sc->offchannel.state == ATH_OFFCHANNEL_IDLE) {
+               ath_dbg(common, CHAN_CTX, "Starting HW scan\n");
                ath_offchannel_next(sc);
+       }
 
 out:
        mutex_unlock(&sc->mutex);
@@ -2443,6 +2148,9 @@ static void ath9k_cancel_hw_scan(struct ieee80211_hw *hw,
                                 struct ieee80211_vif *vif)
 {
        struct ath_softc *sc = hw->priv;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+       ath_dbg(common, CHAN_CTX, "Cancel HW scan on vif: %pM\n", vif->addr);
 
        mutex_lock(&sc->mutex);
        del_timer_sync(&sc->offchannel.timer);
@@ -2456,6 +2164,7 @@ static int ath9k_remain_on_channel(struct ieee80211_hw *hw,
                                   enum ieee80211_roc_type type)
 {
        struct ath_softc *sc = hw->priv;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        int ret = 0;
 
        mutex_lock(&sc->mutex);
@@ -2470,8 +2179,14 @@ static int ath9k_remain_on_channel(struct ieee80211_hw *hw,
        sc->offchannel.roc_chan = chan;
        sc->offchannel.roc_duration = duration;
 
-       if (sc->offchannel.state == ATH_OFFCHANNEL_IDLE)
+       ath_dbg(common, CHAN_CTX,
+               "RoC request on vif: %pM, type: %d duration: %d\n",
+               vif->addr, type, duration);
+
+       if (sc->offchannel.state == ATH_OFFCHANNEL_IDLE) {
+               ath_dbg(common, CHAN_CTX, "Starting RoC period\n");
                ath_offchannel_next(sc);
+       }
 
 out:
        mutex_unlock(&sc->mutex);
@@ -2482,9 +2197,11 @@ out:
 static int ath9k_cancel_remain_on_channel(struct ieee80211_hw *hw)
 {
        struct ath_softc *sc = hw->priv;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 
        mutex_lock(&sc->mutex);
 
+       ath_dbg(common, CHAN_CTX, "Cancel RoC\n");
        del_timer_sync(&sc->offchannel.timer);
 
        if (sc->offchannel.roc_vif) {
@@ -2501,6 +2218,7 @@ static int ath9k_add_chanctx(struct ieee80211_hw *hw,
                             struct ieee80211_chanctx_conf *conf)
 {
        struct ath_softc *sc = hw->priv;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_chanctx *ctx, **ptr;
        int pos;
 
@@ -2515,10 +2233,18 @@ static int ath9k_add_chanctx(struct ieee80211_hw *hw,
                ctx->assigned = true;
                pos = ctx - &sc->chanctx[0];
                ctx->hw_queue_base = pos * IEEE80211_NUM_ACS;
+
+               ath_dbg(common, CHAN_CTX,
+                       "Add channel context: %d MHz\n",
+                       conf->def.chan->center_freq);
+
                ath_chanctx_set_channel(sc, ctx, &conf->def);
+               ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_ASSIGN);
+
                mutex_unlock(&sc->mutex);
                return 0;
        }
+
        mutex_unlock(&sc->mutex);
        return -ENOSPC;
 }
@@ -2528,12 +2254,19 @@ static void ath9k_remove_chanctx(struct ieee80211_hw *hw,
                                 struct ieee80211_chanctx_conf *conf)
 {
        struct ath_softc *sc = hw->priv;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_chanctx *ctx = ath_chanctx_get(conf);
 
        mutex_lock(&sc->mutex);
+
+       ath_dbg(common, CHAN_CTX,
+               "Remove channel context: %d MHz\n",
+               conf->def.chan->center_freq);
+
        ctx->assigned = false;
        ctx->hw_queue_base = -1;
        ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_UNASSIGN);
+
        mutex_unlock(&sc->mutex);
 }
 
@@ -2542,9 +2275,13 @@ static void ath9k_change_chanctx(struct ieee80211_hw *hw,
                                 u32 changed)
 {
        struct ath_softc *sc = hw->priv;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_chanctx *ctx = ath_chanctx_get(conf);
 
        mutex_lock(&sc->mutex);
+       ath_dbg(common, CHAN_CTX,
+               "Change channel context: %d MHz\n",
+               conf->def.chan->center_freq);
        ath_chanctx_set_channel(sc, ctx, &conf->def);
        mutex_unlock(&sc->mutex);
 }
@@ -2554,16 +2291,24 @@ static int ath9k_assign_vif_chanctx(struct ieee80211_hw *hw,
                                    struct ieee80211_chanctx_conf *conf)
 {
        struct ath_softc *sc = hw->priv;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_vif *avp = (void *)vif->drv_priv;
        struct ath_chanctx *ctx = ath_chanctx_get(conf);
        int i;
 
        mutex_lock(&sc->mutex);
+
+       ath_dbg(common, CHAN_CTX,
+               "Assign VIF (addr: %pM, type: %d, p2p: %d) to channel context: %d MHz\n",
+               vif->addr, vif->type, vif->p2p,
+               conf->def.chan->center_freq);
+
        avp->chanctx = ctx;
        list_add_tail(&avp->list, &ctx->vifs);
        ath9k_calculate_summary_state(sc, ctx);
        for (i = 0; i < IEEE80211_NUM_ACS; i++)
                vif->hw_queue[i] = ctx->hw_queue_base + i;
+
        mutex_unlock(&sc->mutex);
 
        return 0;
@@ -2574,36 +2319,79 @@ static void ath9k_unassign_vif_chanctx(struct ieee80211_hw *hw,
                                       struct ieee80211_chanctx_conf *conf)
 {
        struct ath_softc *sc = hw->priv;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_vif *avp = (void *)vif->drv_priv;
        struct ath_chanctx *ctx = ath_chanctx_get(conf);
        int ac;
 
        mutex_lock(&sc->mutex);
+
+       ath_dbg(common, CHAN_CTX,
+               "Remove VIF (addr: %pM, type: %d, p2p: %d) from channel context: %d MHz\n",
+               vif->addr, vif->type, vif->p2p,
+               conf->def.chan->center_freq);
+
        avp->chanctx = NULL;
        list_del(&avp->list);
        ath9k_calculate_summary_state(sc, ctx);
        for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
                vif->hw_queue[ac] = IEEE80211_INVAL_HW_QUEUE;
+
+       mutex_unlock(&sc->mutex);
+}
+
+static void ath9k_mgd_prepare_tx(struct ieee80211_hw *hw,
+                                struct ieee80211_vif *vif)
+{
+       struct ath_softc *sc = hw->priv;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       struct ath_vif *avp = (struct ath_vif *) vif->drv_priv;
+       bool changed = false;
+
+       if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
+               return;
+
+       if (!avp->chanctx)
+               return;
+
+       mutex_lock(&sc->mutex);
+
+       spin_lock_bh(&sc->chan_lock);
+       if (sc->next_chan || (sc->cur_chan != avp->chanctx)) {
+               sc->next_chan = avp->chanctx;
+               changed = true;
+       }
+       ath_dbg(common, CHAN_CTX,
+               "%s: Set chanctx state to FORCE_ACTIVE, changed: %d\n",
+               __func__, changed);
+       sc->sched.state = ATH_CHANCTX_STATE_FORCE_ACTIVE;
+       spin_unlock_bh(&sc->chan_lock);
+
+       if (changed)
+               ath_chanctx_set_next(sc, true);
+
        mutex_unlock(&sc->mutex);
 }
 
 void ath9k_fill_chanctx_ops(void)
 {
-       if (!ath9k_use_chanctx)
+       if (!ath9k_is_chanctx_enabled())
                return;
 
-       ath9k_ops.hw_scan = ath9k_hw_scan;
-       ath9k_ops.cancel_hw_scan = ath9k_cancel_hw_scan;
-       ath9k_ops.remain_on_channel  = ath9k_remain_on_channel;
+       ath9k_ops.hw_scan                  = ath9k_hw_scan;
+       ath9k_ops.cancel_hw_scan           = ath9k_cancel_hw_scan;
+       ath9k_ops.remain_on_channel        = ath9k_remain_on_channel;
        ath9k_ops.cancel_remain_on_channel = ath9k_cancel_remain_on_channel;
-       ath9k_ops.add_chanctx        = ath9k_add_chanctx;
-       ath9k_ops.remove_chanctx     = ath9k_remove_chanctx;
-       ath9k_ops.change_chanctx     = ath9k_change_chanctx;
-       ath9k_ops.assign_vif_chanctx = ath9k_assign_vif_chanctx;
-       ath9k_ops.unassign_vif_chanctx = ath9k_unassign_vif_chanctx;
-       ath9k_ops.mgd_prepare_tx = ath9k_chanctx_force_active;
+       ath9k_ops.add_chanctx              = ath9k_add_chanctx;
+       ath9k_ops.remove_chanctx           = ath9k_remove_chanctx;
+       ath9k_ops.change_chanctx           = ath9k_change_chanctx;
+       ath9k_ops.assign_vif_chanctx       = ath9k_assign_vif_chanctx;
+       ath9k_ops.unassign_vif_chanctx     = ath9k_unassign_vif_chanctx;
+       ath9k_ops.mgd_prepare_tx           = ath9k_mgd_prepare_tx;
 }
 
+#endif
+
 struct ieee80211_ops ath9k_ops = {
        .tx                 = ath9k_tx,
        .start              = ath9k_start,
index 74ab1d02013bf002bf04c0cfd197a2ecd8cdc29a..2aaf233ee5d68cf7e937538c2ab3d211152f90bb 100644 (file)
@@ -425,7 +425,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
        if (AR_SREV_9550(sc->sc_ah) || AR_SREV_9531(sc->sc_ah))
                rfilt |= ATH9K_RX_FILTER_4ADDRESS;
 
-       if (ath9k_use_chanctx &&
+       if (ath9k_is_chanctx_enabled() &&
            test_bit(ATH_OP_SCANNING, &common->op_flags))
                rfilt |= ATH9K_RX_FILTER_BEACON;
 
@@ -547,8 +547,8 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
                        "Reconfigure beacon timers based on synchronized timestamp\n");
                if (!(WARN_ON_ONCE(sc->cur_chan->beacon.beacon_interval == 0)))
                        ath9k_set_beacon(sc);
-               if (sc->p2p_ps_vif)
-                       ath9k_update_p2p_ps(sc, sc->p2p_ps_vif->vif);
+
+               ath9k_p2p_beacon_sync(sc);
        }
 
        if (ath_beacon_dtim_pending_cab(skb)) {
@@ -892,9 +892,10 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
                return -EINVAL;
        }
 
-       if (rx_stats->is_mybeacon) {
-               sc->sched.next_tbtt = rx_stats->rs_tstamp;
-               ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_BEACON_RECEIVED);
+       if (ath9k_is_chanctx_enabled()) {
+               if (rx_stats->is_mybeacon)
+                       ath_chanctx_beacon_recv_ev(sc, rx_stats->rs_tstamp,
+                                          ATH_CHANCTX_EVENT_BEACON_RECEIVED);
        }
 
        ath9k_cmn_process_rssi(common, hw, rx_stats, rx_status);
index 5fe29b9f8fa26e31b05eaab237ac4830aaf21471..8f68426ca653d93dc58ea990a213c7091a13553a 100644 (file)
@@ -253,7 +253,7 @@ static ssize_t write_file_spec_scan_ctl(struct file *file,
 
        if (strncmp("trigger", buf, 7) == 0) {
                ath9k_spectral_scan_trigger(sc->hw);
-       } else if (strncmp("background", buf, 9) == 0) {
+       } else if (strncmp("background", buf, 10) == 0) {
                ath9k_spectral_scan_config(sc->hw, SPECTRAL_BACKGROUND);
                ath_dbg(common, CONFIG, "spectral scan: background mode enabled\n");
        } else if (strncmp("chanscan", buf, 8) == 0) {
index ead63412ee1ae9b6137f14b2299d3bbc243340d6..7b410c6858b08741a4bf5bcea49b458ebe5c4e79 100644 (file)
@@ -17,6 +17,8 @@
 #ifndef SPECTRAL_H
 #define SPECTRAL_H
 
+#include "../spectral_common.h"
+
 /* enum spectral_mode:
  *
  * @SPECTRAL_DISABLED: spectral mode is disabled
@@ -54,8 +56,6 @@ struct ath_ht20_mag_info {
        u8 max_exp;
 } __packed;
 
-#define SPECTRAL_HT20_NUM_BINS         56
-
 /* WARNING: don't actually use this struct! MAC may vary the amount of
  * data by -1/+2. This struct is for reference only.
  */
@@ -83,8 +83,6 @@ struct ath_ht20_40_mag_info {
        u8 max_exp;
 } __packed;
 
-#define SPECTRAL_HT20_40_NUM_BINS              128
-
 /* WARNING: don't actually use this struct! MAC may vary the amount of
  * data. This struct is for reference only.
  */
@@ -125,71 +123,6 @@ static inline u8 spectral_bitmap_weight(u8 *bins)
        return bins[0] & 0x3f;
 }
 
-/* FFT sample format given to userspace via debugfs.
- *
- * Please keep the type/length at the front position and change
- * other fields after adding another sample type
- *
- * TODO: this might need rework when switching to nl80211-based
- * interface.
- */
-enum ath_fft_sample_type {
-       ATH_FFT_SAMPLE_HT20 = 1,
-       ATH_FFT_SAMPLE_HT20_40,
-};
-
-struct fft_sample_tlv {
-       u8 type;        /* see ath_fft_sample */
-       __be16 length;
-       /* type dependent data follows */
-} __packed;
-
-struct fft_sample_ht20 {
-       struct fft_sample_tlv tlv;
-
-       u8 max_exp;
-
-       __be16 freq;
-       s8 rssi;
-       s8 noise;
-
-       __be16 max_magnitude;
-       u8 max_index;
-       u8 bitmap_weight;
-
-       __be64 tsf;
-
-       u8 data[SPECTRAL_HT20_NUM_BINS];
-} __packed;
-
-struct fft_sample_ht20_40 {
-       struct fft_sample_tlv tlv;
-
-       u8 channel_type;
-       __be16 freq;
-
-       s8 lower_rssi;
-       s8 upper_rssi;
-
-       __be64 tsf;
-
-       s8 lower_noise;
-       s8 upper_noise;
-
-       __be16 lower_max_magnitude;
-       __be16 upper_max_magnitude;
-
-       u8 lower_max_index;
-       u8 upper_max_index;
-
-       u8 lower_bitmap_weight;
-       u8 upper_bitmap_weight;
-
-       u8 max_exp;
-
-       u8 data[SPECTRAL_HT20_40_NUM_BINS];
-} __packed;
-
 void ath9k_spectral_init_debug(struct ath_softc *sc);
 void ath9k_spectral_deinit_debug(struct ath_softc *sc);
 
index a4f4f0da81f6e2a1cc71349a0c68185a2f07e546..33531d9a4d50cbee3530d260aedcc60f9df74bb7 100644 (file)
@@ -193,7 +193,8 @@ int ath9k_suspend(struct ieee80211_hw *hw,
        u32 wow_triggers_enabled = 0;
        int ret = 0;
 
-       cancel_work_sync(&sc->chanctx_work);
+       ath9k_deinit_channel_context(sc);
+
        mutex_lock(&sc->mutex);
 
        ath_cancel_work(sc);
index 704fcbcbe20b5a59723063c77ac0d98ee482a99f..281986613fb2fe7acd705b41e36d4bbc45f5807b 100644 (file)
@@ -2632,8 +2632,11 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)
                        sc->beacon.tx_processed = true;
                        sc->beacon.tx_last = !(ts.ts_status & ATH9K_TXERR_MASK);
 
-                       ath_chanctx_event(sc, NULL,
-                                         ATH_CHANCTX_EVENT_BEACON_SENT);
+                       if (ath9k_is_chanctx_enabled()) {
+                               ath_chanctx_event(sc, NULL,
+                                                 ATH_CHANCTX_EVENT_BEACON_SENT);
+                       }
+
                        ath9k_csa_update(sc);
                        continue;
                }
index f8ded84b7be8c5e3b6038910a8829364a5e5ba1e..ef5b6dc7b7f17b52388ba45132e836aa0ff37bf4 100644 (file)
@@ -1430,18 +1430,10 @@ static int carl9170_op_ampdu_action(struct ieee80211_hw *hw,
                if (!sta_info->ht_sta)
                        return -EOPNOTSUPP;
 
-               rcu_read_lock();
-               if (rcu_dereference(sta_info->agg[tid])) {
-                       rcu_read_unlock();
-                       return -EBUSY;
-               }
-
                tid_info = kzalloc(sizeof(struct carl9170_sta_tid),
                                   GFP_ATOMIC);
-               if (!tid_info) {
-                       rcu_read_unlock();
+               if (!tid_info)
                        return -ENOMEM;
-               }
 
                tid_info->hsn = tid_info->bsn = tid_info->snx = (*ssn);
                tid_info->state = CARL9170_TID_STATE_PROGRESS;
@@ -1460,7 +1452,6 @@ static int carl9170_op_ampdu_action(struct ieee80211_hw *hw,
                list_add_tail_rcu(&tid_info->list, &ar->tx_ampdu_list);
                rcu_assign_pointer(sta_info->agg[tid], tid_info);
                spin_unlock_bh(&ar->tx_ampdu_list_lock);
-               rcu_read_unlock();
 
                ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
                break;
index 4cadfd48ffdf8bd19f0206c138337f2e58177622..ae86a600d9207a4a59530710daae08f857155d34 100644 (file)
@@ -1557,7 +1557,7 @@ static struct carl9170_vif_info *carl9170_pick_beaconing_vif(struct ar9170 *ar)
        }
 
 out:
-       rcu_assign_pointer(ar->beacon_iter, cvif);
+       RCU_INIT_POINTER(ar->beacon_iter, cvif);
        return cvif;
 }
 
diff --git a/drivers/net/wireless/ath/spectral_common.h b/drivers/net/wireless/ath/spectral_common.h
new file mode 100644 (file)
index 0000000..0d742ac
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2013 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef SPECTRAL_COMMON_H
+#define SPECTRAL_COMMON_H
+
+#define SPECTRAL_HT20_NUM_BINS         56
+#define SPECTRAL_HT20_40_NUM_BINS              128
+
+/* TODO: could possibly be 512, but no samples this large
+ * could be acquired so far.
+ */
+#define SPECTRAL_ATH10K_MAX_NUM_BINS           256
+
+/* FFT sample format given to userspace via debugfs.
+ *
+ * Please keep the type/length at the front position and change
+ * other fields after adding another sample type
+ *
+ * TODO: this might need rework when switching to nl80211-based
+ * interface.
+ */
+enum ath_fft_sample_type {
+       ATH_FFT_SAMPLE_HT20 = 1,
+       ATH_FFT_SAMPLE_HT20_40,
+       ATH_FFT_SAMPLE_ATH10K,
+};
+
+struct fft_sample_tlv {
+       u8 type;        /* see ath_fft_sample */
+       __be16 length;
+       /* type dependent data follows */
+} __packed;
+
+struct fft_sample_ht20 {
+       struct fft_sample_tlv tlv;
+
+       u8 max_exp;
+
+       __be16 freq;
+       s8 rssi;
+       s8 noise;
+
+       __be16 max_magnitude;
+       u8 max_index;
+       u8 bitmap_weight;
+
+       __be64 tsf;
+
+       u8 data[SPECTRAL_HT20_NUM_BINS];
+} __packed;
+
+struct fft_sample_ht20_40 {
+       struct fft_sample_tlv tlv;
+
+       u8 channel_type;
+       __be16 freq;
+
+       s8 lower_rssi;
+       s8 upper_rssi;
+
+       __be64 tsf;
+
+       s8 lower_noise;
+       s8 upper_noise;
+
+       __be16 lower_max_magnitude;
+       __be16 upper_max_magnitude;
+
+       u8 lower_max_index;
+       u8 upper_max_index;
+
+       u8 lower_bitmap_weight;
+       u8 upper_bitmap_weight;
+
+       u8 max_exp;
+
+       u8 data[SPECTRAL_HT20_40_NUM_BINS];
+} __packed;
+
+struct fft_sample_ath10k {
+       struct fft_sample_tlv tlv;
+       u8 chan_width_mhz;
+       __be16 freq1;
+       __be16 freq2;
+       __be16 noise;
+       __be16 max_magnitude;
+       __be16 total_gain_db;
+       __be16 base_pwr_db;
+       __be64 tsf;
+       s8 max_index;
+       u8 rssi;
+       u8 relpwr_db;
+       u8 avgpwr_db;
+       u8 max_exp;
+
+       u8 data[0];
+} __packed;
+
+#endif /* SPECTRAL_COMMON_H */
index 4ac2c208c9ba3ff109e8c8942b1b9637e9b7cf0d..a00f31881df94ba0068b40891afea709066090de 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -311,8 +311,10 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
        rc = wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) +
                        cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0]));
 
-       if (rc)
+       if (rc) {
+               del_timer_sync(&wil->scan_timer);
                wil->scan_request = NULL;
+       }
 
        return rc;
 }
index 8f66186adb8c59d67103ad75ddb759063736bbaa..b1c6a7293390a4364450c778b1ed24b156a2c77d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -22,6 +22,7 @@
 #include <linux/power_supply.h>
 
 #include "wil6210.h"
+#include "wmi.h"
 #include "txrx.h"
 
 /* Nasty hack. Better have per device instances */
@@ -29,6 +30,21 @@ static u32 mem_addr;
 static u32 dbg_txdesc_index;
 static u32 dbg_vring_index; /* 24+ for Rx, 0..23 for Tx */
 
+enum dbg_off_type {
+       doff_u32 = 0,
+       doff_x32 = 1,
+       doff_ulong = 2,
+       doff_io32 = 3,
+};
+
+/* offset to "wil" */
+struct dbg_off {
+       const char *name;
+       umode_t mode;
+       ulong off;
+       enum dbg_off_type type;
+};
+
 static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil,
                            const char *name, struct vring *vring,
                            char _s, char _h)
@@ -244,9 +260,9 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, wil_debugfs_iomem_x32_get,
 static struct dentry *wil_debugfs_create_iomem_x32(const char *name,
                                                   umode_t mode,
                                                   struct dentry *parent,
-                                                  void __iomem *value)
+                                                  void *value)
 {
-       return debugfs_create_file(name, mode, parent, (void * __force)value,
+       return debugfs_create_file(name, mode, parent, value,
                                   &fops_iomem_x32);
 }
 
@@ -270,6 +286,59 @@ static struct dentry *wil_debugfs_create_ulong(const char *name, umode_t mode,
        return debugfs_create_file(name, mode, parent, value, &wil_fops_ulong);
 }
 
+/**
+ * wil6210_debugfs_init_offset - create set of debugfs files
+ * @wil - driver's context, used for printing
+ * @dbg - directory on the debugfs, where files will be created
+ * @base - base address used in address calculation
+ * @tbl - table with file descriptions. Should be terminated with empty element.
+ *
+ * Creates files accordingly to the @tbl.
+ */
+static void wil6210_debugfs_init_offset(struct wil6210_priv *wil,
+                                       struct dentry *dbg, void *base,
+                                       const struct dbg_off * const tbl)
+{
+       int i;
+
+       for (i = 0; tbl[i].name; i++) {
+               struct dentry *f = NULL;
+
+               switch (tbl[i].type) {
+               case doff_u32:
+                       f = debugfs_create_u32(tbl[i].name, tbl[i].mode, dbg,
+                                              base + tbl[i].off);
+                       break;
+               case doff_x32:
+                       f = debugfs_create_x32(tbl[i].name, tbl[i].mode, dbg,
+                                              base + tbl[i].off);
+                       break;
+               case doff_ulong:
+                       f = wil_debugfs_create_ulong(tbl[i].name, tbl[i].mode,
+                                                    dbg, base + tbl[i].off);
+                       break;
+               case doff_io32:
+                       f = wil_debugfs_create_iomem_x32(tbl[i].name,
+                                                        tbl[i].mode, dbg,
+                                                        base + tbl[i].off);
+                       break;
+               }
+               if (IS_ERR_OR_NULL(f))
+                       wil_err(wil, "Create file \"%s\": err %ld\n",
+                               tbl[i].name, PTR_ERR(f));
+       }
+}
+
+static const struct dbg_off isr_off[] = {
+       {"ICC", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, ICC), doff_io32},
+       {"ICR", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, ICR), doff_io32},
+       {"ICM", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, ICM), doff_io32},
+       {"ICS",           S_IWUSR, offsetof(struct RGF_ICR, ICS), doff_io32},
+       {"IMV", S_IRUGO | S_IWUSR, offsetof(struct RGF_ICR, IMV), doff_io32},
+       {"IMS",           S_IWUSR, offsetof(struct RGF_ICR, IMS), doff_io32},
+       {"IMC",           S_IWUSR, offsetof(struct RGF_ICR, IMC), doff_io32},
+       {},
+};
 static int wil6210_debugfs_create_ISR(struct wil6210_priv *wil,
                                      const char *name,
                                      struct dentry *parent, u32 off)
@@ -279,24 +348,19 @@ static int wil6210_debugfs_create_ISR(struct wil6210_priv *wil,
        if (IS_ERR_OR_NULL(d))
                return -ENODEV;
 
-       wil_debugfs_create_iomem_x32("ICC", S_IRUGO | S_IWUSR, d,
-                                    wil->csr + off);
-       wil_debugfs_create_iomem_x32("ICR", S_IRUGO | S_IWUSR, d,
-                                    wil->csr + off + 4);
-       wil_debugfs_create_iomem_x32("ICM", S_IRUGO | S_IWUSR, d,
-                                    wil->csr + off + 8);
-       wil_debugfs_create_iomem_x32("ICS", S_IWUSR, d,
-                                    wil->csr + off + 12);
-       wil_debugfs_create_iomem_x32("IMV", S_IRUGO | S_IWUSR, d,
-                                    wil->csr + off + 16);
-       wil_debugfs_create_iomem_x32("IMS", S_IWUSR, d,
-                                    wil->csr + off + 20);
-       wil_debugfs_create_iomem_x32("IMC", S_IWUSR, d,
-                                    wil->csr + off + 24);
+       wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr + off,
+                                   isr_off);
 
        return 0;
 }
 
+static const struct dbg_off pseudo_isr_off[] = {
+       {"CAUSE",   S_IRUGO, HOSTADDR(RGF_DMA_PSEUDO_CAUSE), doff_io32},
+       {"MASK_SW", S_IRUGO, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW), doff_io32},
+       {"MASK_FW", S_IRUGO, HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_FW), doff_io32},
+       {},
+};
+
 static int wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv *wil,
                                             struct dentry *parent)
 {
@@ -305,16 +369,19 @@ static int wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv *wil,
        if (IS_ERR_OR_NULL(d))
                return -ENODEV;
 
-       wil_debugfs_create_iomem_x32("CAUSE", S_IRUGO, d, wil->csr +
-                                    HOSTADDR(RGF_DMA_PSEUDO_CAUSE));
-       wil_debugfs_create_iomem_x32("MASK_SW", S_IRUGO, d, wil->csr +
-                                    HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW));
-       wil_debugfs_create_iomem_x32("MASK_FW", S_IRUGO, d, wil->csr +
-                                    HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_FW));
+       wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr,
+                                   pseudo_isr_off);
 
        return 0;
 }
 
+static const struct dbg_off itr_cnt_off[] = {
+       {"TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_TRSH), doff_io32},
+       {"DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_DATA), doff_io32},
+       {"CTL",  S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_CRL), doff_io32},
+       {},
+};
+
 static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil,
                                          struct dentry *parent)
 {
@@ -323,12 +390,8 @@ static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil,
        if (IS_ERR_OR_NULL(d))
                return -ENODEV;
 
-       wil_debugfs_create_iomem_x32("TRSH", S_IRUGO | S_IWUSR, d, wil->csr +
-                                    HOSTADDR(RGF_DMA_ITR_CNT_TRSH));
-       wil_debugfs_create_iomem_x32("DATA", S_IRUGO | S_IWUSR, d, wil->csr +
-                                    HOSTADDR(RGF_DMA_ITR_CNT_DATA));
-       wil_debugfs_create_iomem_x32("CTL", S_IRUGO | S_IWUSR, d, wil->csr +
-                                    HOSTADDR(RGF_DMA_ITR_CNT_CRL));
+       wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr,
+                                   itr_cnt_off);
 
        return 0;
 }
@@ -666,16 +729,79 @@ static const struct file_operations fops_txdesc = {
 };
 
 /*---------beamforming------------*/
+static char *wil_bfstatus_str(u32 status)
+{
+       switch (status) {
+       case 0:
+               return "Failed";
+       case 1:
+               return "OK";
+       case 2:
+               return "Retrying";
+       default:
+               return "??";
+       }
+}
+
+static bool is_all_zeros(void * const x_, size_t sz)
+{
+       /* if reply is all-0, ignore this CID */
+       u32 *x = x_;
+       int n;
+
+       for (n = 0; n < sz / sizeof(*x); n++)
+               if (x[n])
+                       return false;
+
+       return true;
+}
+
 static int wil_bf_debugfs_show(struct seq_file *s, void *data)
 {
+       int rc;
+       int i;
        struct wil6210_priv *wil = s->private;
-       seq_printf(s,
-                  "TSF : 0x%016llx\n"
-                  "TxMCS : %d\n"
-                  "Sectors(rx:tx) my %2d:%2d peer %2d:%2d\n",
-                  wil->stats.tsf, wil->stats.bf_mcs,
-                  wil->stats.my_rx_sector, wil->stats.my_tx_sector,
-                  wil->stats.peer_rx_sector, wil->stats.peer_tx_sector);
+       struct wmi_notify_req_cmd cmd = {
+               .interval_usec = 0,
+       };
+       struct {
+               struct wil6210_mbox_hdr_wmi wmi;
+               struct wmi_notify_req_done_event evt;
+       } __packed reply;
+
+       for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
+               u32 status;
+
+               cmd.cid = i;
+               rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd),
+                             WMI_NOTIFY_REQ_DONE_EVENTID, &reply,
+                             sizeof(reply), 20);
+               /* if reply is all-0, ignore this CID */
+               if (rc || is_all_zeros(&reply.evt, sizeof(reply.evt)))
+                       continue;
+
+               status = le32_to_cpu(reply.evt.status);
+               seq_printf(s, "CID %d {\n"
+                          "  TSF = 0x%016llx\n"
+                          "  TxMCS = %2d TxTpt = %4d\n"
+                          "  SQI = %4d\n"
+                          "  Status = 0x%08x %s\n"
+                          "  Sectors(rx:tx) my %2d:%2d peer %2d:%2d\n"
+                          "  Goodput(rx:tx) %4d:%4d\n"
+                          "}\n",
+                          i,
+                          le64_to_cpu(reply.evt.tsf),
+                          le16_to_cpu(reply.evt.bf_mcs),
+                          le32_to_cpu(reply.evt.tx_tpt),
+                          reply.evt.sqi,
+                          status, wil_bfstatus_str(status),
+                          le16_to_cpu(reply.evt.my_rx_sector),
+                          le16_to_cpu(reply.evt.my_tx_sector),
+                          le16_to_cpu(reply.evt.other_rx_sector),
+                          le16_to_cpu(reply.evt.other_tx_sector),
+                          le32_to_cpu(reply.evt.rx_goodput),
+                          le32_to_cpu(reply.evt.tx_goodput));
+       }
        return 0;
 }
 
@@ -985,6 +1111,87 @@ static void wil6210_debugfs_init_blobs(struct wil6210_priv *wil,
        }
 }
 
+/* misc files */
+static const struct {
+       const char *name;
+       umode_t mode;
+       const struct file_operations *fops;
+} dbg_files[] = {
+       {"mbox",        S_IRUGO,                &fops_mbox},
+       {"vrings",      S_IRUGO,                &fops_vring},
+       {"stations",    S_IRUGO,                &fops_sta},
+       {"desc",        S_IRUGO,                &fops_txdesc},
+       {"bf",          S_IRUGO,                &fops_bf},
+       {"ssid",        S_IRUGO | S_IWUSR,      &fops_ssid},
+       {"mem_val",     S_IRUGO,                &fops_memread},
+       {"reset",                 S_IWUSR,      &fops_reset},
+       {"rxon",                  S_IWUSR,      &fops_rxon},
+       {"tx_mgmt",               S_IWUSR,      &fops_txmgmt},
+       {"wmi_send",              S_IWUSR,      &fops_wmi},
+       {"temp",        S_IRUGO,                &fops_temp},
+       {"freq",        S_IRUGO,                &fops_freq},
+       {"link",        S_IRUGO,                &fops_link},
+       {"info",        S_IRUGO,                &fops_info},
+};
+
+static void wil6210_debugfs_init_files(struct wil6210_priv *wil,
+                                      struct dentry *dbg)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(dbg_files); i++)
+               debugfs_create_file(dbg_files[i].name, dbg_files[i].mode, dbg,
+                                   wil, dbg_files[i].fops);
+}
+
+/* interrupt control blocks */
+static const struct {
+       const char *name;
+       u32 icr_off;
+} dbg_icr[] = {
+       {"USER_ICR",            HOSTADDR(RGF_USER_USER_ICR)},
+       {"DMA_EP_TX_ICR",       HOSTADDR(RGF_DMA_EP_TX_ICR)},
+       {"DMA_EP_RX_ICR",       HOSTADDR(RGF_DMA_EP_RX_ICR)},
+       {"DMA_EP_MISC_ICR",     HOSTADDR(RGF_DMA_EP_MISC_ICR)},
+};
+
+static void wil6210_debugfs_init_isr(struct wil6210_priv *wil,
+                                    struct dentry *dbg)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(dbg_icr); i++)
+               wil6210_debugfs_create_ISR(wil, dbg_icr[i].name, dbg,
+                                          dbg_icr[i].icr_off);
+}
+
+#define WIL_FIELD(name, mode, type) { __stringify(name), mode, \
+       offsetof(struct wil6210_priv, name), type}
+
+/* fields in struct wil6210_priv */
+static const struct dbg_off dbg_wil_off[] = {
+       WIL_FIELD(secure_pcp,   S_IRUGO | S_IWUSR,      doff_u32),
+       WIL_FIELD(status,       S_IRUGO | S_IWUSR,      doff_ulong),
+       WIL_FIELD(fw_version,   S_IRUGO,                doff_u32),
+       WIL_FIELD(hw_version,   S_IRUGO,                doff_x32),
+       {},
+};
+
+static const struct dbg_off dbg_wil_regs[] = {
+       {"RGF_MAC_MTRL_COUNTER_0", S_IRUGO, HOSTADDR(RGF_MAC_MTRL_COUNTER_0),
+               doff_io32},
+       {"RGF_USER_USAGE_1", S_IRUGO, HOSTADDR(RGF_USER_USAGE_1), doff_io32},
+       {},
+};
+
+/* static parameters */
+static const struct dbg_off dbg_statics[] = {
+       {"desc_index",  S_IRUGO | S_IWUSR, (ulong)&dbg_txdesc_index, doff_u32},
+       {"vring_index", S_IRUGO | S_IWUSR, (ulong)&dbg_vring_index, doff_u32},
+       {"mem_addr",    S_IRUGO | S_IWUSR, (ulong)&mem_addr, doff_u32},
+       {},
+};
+
 int wil6210_debugfs_init(struct wil6210_priv *wil)
 {
        struct dentry *dbg = wil->debug = debugfs_create_dir(WIL_NAME,
@@ -993,51 +1200,17 @@ int wil6210_debugfs_init(struct wil6210_priv *wil)
        if (IS_ERR_OR_NULL(dbg))
                return -ENODEV;
 
-       debugfs_create_file("mbox", S_IRUGO, dbg, wil, &fops_mbox);
-       debugfs_create_file("vrings", S_IRUGO, dbg, wil, &fops_vring);
-       debugfs_create_file("stations", S_IRUGO, dbg, wil, &fops_sta);
-       debugfs_create_file("desc", S_IRUGO, dbg, wil, &fops_txdesc);
-       debugfs_create_u32("desc_index", S_IRUGO | S_IWUSR, dbg,
-                          &dbg_txdesc_index);
-       debugfs_create_u32("vring_index", S_IRUGO | S_IWUSR, dbg,
-                          &dbg_vring_index);
-
-       debugfs_create_file("bf", S_IRUGO, dbg, wil, &fops_bf);
-       debugfs_create_file("ssid", S_IRUGO | S_IWUSR, dbg, wil, &fops_ssid);
-       debugfs_create_u32("secure_pcp", S_IRUGO | S_IWUSR, dbg,
-                          &wil->secure_pcp);
-       wil_debugfs_create_ulong("status", S_IRUGO | S_IWUSR, dbg,
-                                &wil->status);
-       debugfs_create_u32("fw_version", S_IRUGO, dbg, &wil->fw_version);
-       debugfs_create_x32("hw_version", S_IRUGO, dbg, &wil->hw_version);
-
-       wil6210_debugfs_create_ISR(wil, "USER_ICR", dbg,
-                                  HOSTADDR(RGF_USER_USER_ICR));
-       wil6210_debugfs_create_ISR(wil, "DMA_EP_TX_ICR", dbg,
-                                  HOSTADDR(RGF_DMA_EP_TX_ICR));
-       wil6210_debugfs_create_ISR(wil, "DMA_EP_RX_ICR", dbg,
-                                  HOSTADDR(RGF_DMA_EP_RX_ICR));
-       wil6210_debugfs_create_ISR(wil, "DMA_EP_MISC_ICR", dbg,
-                                  HOSTADDR(RGF_DMA_EP_MISC_ICR));
-       wil6210_debugfs_create_pseudo_ISR(wil, dbg);
-       wil6210_debugfs_create_ITR_CNT(wil, dbg);
+       wil6210_debugfs_init_files(wil, dbg);
+       wil6210_debugfs_init_isr(wil, dbg);
+       wil6210_debugfs_init_blobs(wil, dbg);
+       wil6210_debugfs_init_offset(wil, dbg, wil, dbg_wil_off);
+       wil6210_debugfs_init_offset(wil, dbg, (void * __force)wil->csr,
+                                   dbg_wil_regs);
+       wil6210_debugfs_init_offset(wil, dbg, NULL, dbg_statics);
 
-       wil_debugfs_create_iomem_x32("RGF_USER_USAGE_1", S_IRUGO, dbg,
-                                    wil->csr +
-                                    HOSTADDR(RGF_USER_USAGE_1));
-       debugfs_create_u32("mem_addr", S_IRUGO | S_IWUSR, dbg, &mem_addr);
-       debugfs_create_file("mem_val", S_IRUGO, dbg, wil, &fops_memread);
-
-       debugfs_create_file("reset", S_IWUSR, dbg, wil, &fops_reset);
-       debugfs_create_file("rxon", S_IWUSR, dbg, wil, &fops_rxon);
-       debugfs_create_file("tx_mgmt", S_IWUSR, dbg, wil, &fops_txmgmt);
-       debugfs_create_file("wmi_send", S_IWUSR, dbg, wil, &fops_wmi);
-       debugfs_create_file("temp", S_IRUGO, dbg, wil, &fops_temp);
-       debugfs_create_file("freq", S_IRUGO, dbg, wil, &fops_freq);
-       debugfs_create_file("link", S_IRUGO, dbg, wil, &fops_link);
-       debugfs_create_file("info", S_IRUGO, dbg, wil, &fops_info);
+       wil6210_debugfs_create_pseudo_ISR(wil, dbg);
 
-       wil6210_debugfs_init_blobs(wil, dbg);
+       wil6210_debugfs_create_ITR_CNT(wil, dbg);
 
        return 0;
 }
index 67f1002a03a13a88d7224a3a8abea8f234aa9ae2..98bfbb6390b75267618d9c1c67ad83f8be76749c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 3704d2a434f340b4374f26e5bde083b9830e09a3..b69d90f0716ffec424bcb5381da659ab197c1132 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -25,6 +25,9 @@ static bool no_fw_recovery;
 module_param(no_fw_recovery, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(no_fw_recovery, " disable FW error recovery");
 
+#define RST_DELAY (20) /* msec, for loop in @wil_target_reset */
+#define RST_COUNT (1 + 1000/RST_DELAY) /* round up to be above 1 sec total */
+
 /*
  * Due to a hardware issue,
  * one has to read/write to/from NIC in 32-bit chunks;
@@ -309,7 +312,7 @@ void wil_priv_deinit(struct wil6210_priv *wil)
        destroy_workqueue(wil->wmi_wq);
 }
 
-static void wil_target_reset(struct wil6210_priv *wil)
+static int wil_target_reset(struct wil6210_priv *wil)
 {
        int delay = 0;
        u32 hw_state;
@@ -327,6 +330,8 @@ static void wil_target_reset(struct wil6210_priv *wil)
        /* register clear = read, AND with inverted, write */
 #define C(a, v) W(a, R(a) & ~v)
 
+       wmb(); /* If host reorder writes here -> race in NIC */
+       W(RGF_USER_MAC_CPU_0,  BIT(1)); /* mac_cpu_man_rst */
        wil->hw_version = R(RGF_USER_FW_REV_ID);
        rev_id = wil->hw_version & 0xff;
 
@@ -343,8 +348,9 @@ static void wil_target_reset(struct wil6210_priv *wil)
                wmb(); /* order is important here */
        }
 
-       W(RGF_USER_MAC_CPU_0,  BIT(1)); /* mac_cpu_man_rst */
        W(RGF_USER_USER_CPU_0, BIT(1)); /* user_cpu_man_rst */
+       wmb(); /* If host reorder writes here -> race in NIC */
+       W(RGF_USER_MAC_CPU_0,  BIT(1)); /* mac_cpu_man_rst */
        wmb(); /* order is important here */
 
        W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000);
@@ -385,14 +391,14 @@ static void wil_target_reset(struct wil6210_priv *wil)
        W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
        wmb(); /* order is important here */
 
-       /* wait until device ready */
+       /* wait until device ready. typical time is 200..250 msec */
        do {
-               msleep(1);
+               msleep(RST_DELAY);
                hw_state = R(RGF_USER_HW_MACHINE_STATE);
-               if (delay++ > 100) {
+               if (delay++ > RST_COUNT) {
                        wil_err(wil, "Reset not completed, hw_state 0x%08x\n",
                                hw_state);
-                       return;
+                       return -ETIME;
                }
        } while (hw_state != HW_MACHINE_BOOT_DONE);
 
@@ -403,7 +409,8 @@ static void wil_target_reset(struct wil6210_priv *wil)
        C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);
        wmb(); /* order is important here */
 
-       wil_dbg_misc(wil, "Reset completed in %d ms\n", delay);
+       wil_dbg_misc(wil, "Reset completed in %d ms\n", delay * RST_DELAY);
+       return 0;
 
 #undef R
 #undef W
@@ -468,10 +475,11 @@ int wil_reset(struct wil6210_priv *wil)
        flush_workqueue(wil->wmi_wq_conn);
        flush_workqueue(wil->wmi_wq);
 
-       /* TODO: put MAC in reset */
-       wil_target_reset(wil);
-
+       rc = wil_target_reset(wil);
        wil_rx_fini(wil);
+       if (rc)
+               return rc;
+
 
        /* init after reset */
        wil->pending_connect_cid = -1;
index 7afce6e8c5078fb92257a64f6c1e3fabaa65298c..a44c2b61be0850803a66432fa1df3c2a9d1f792e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -168,11 +168,15 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr)
 void wil_if_free(struct wil6210_priv *wil)
 {
        struct net_device *ndev = wil_to_ndev(wil);
+
        if (!ndev)
                return;
 
-       free_netdev(ndev);
        wil_priv_deinit(wil);
+
+       wil_to_ndev(wil) = NULL;
+       free_netdev(ndev);
+
        wil_wdev_free(wil);
 }
 
index d3fbfa28db62c8af2c95f824f9801b516635abff..38dcbea49d449a650ad79c810608bcc8785d1dbd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -218,12 +218,13 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 static void wil_pcie_remove(struct pci_dev *pdev)
 {
        struct wil6210_priv *wil = pci_get_drvdata(pdev);
+       void __iomem *csr = wil->csr;
 
        wil6210_debugfs_remove(wil);
        wil_if_pcie_disable(wil);
        wil_if_remove(wil);
        wil_if_free(wil);
-       pci_iounmap(pdev, wil->csr);
+       pci_iounmap(pdev, csr);
        pci_release_region(pdev, 0);
        pci_disable_device(pdev);
 }
@@ -243,6 +244,8 @@ static const struct pci_device_id wil6210_pcie_ids[] = {
          .driver_data = (kernel_ulong_t)&wil_board_marlon },
        { PCI_DEVICE(0x1ae9, 0x0310),
          .driver_data = (kernel_ulong_t)&wil_board_sparrow },
+       { PCI_DEVICE(0x1ae9, 0x0302), /* same as above, firmware broken */
+         .driver_data = (kernel_ulong_t)&wil_board_sparrow },
        { /* end: all zeroes */ },
 };
 MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids);
index 180ca4793904a37d7723198f5652b02e95142430..97c6a24716a1bc0012ee802ed457ba2c9c3587e9 100644 (file)
@@ -1,3 +1,19 @@
+/*
+ * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
 #include "wil6210.h"
 #include "txrx.h"
 
index d3467943d39db60972bae0ce0413b4e5eaa04585..9bd920d272bbf7c1d20edd165ddeac6aeb342041 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -414,7 +414,6 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
        cid = wil_rxdesc_cid(d);
        stats = &wil->sta[cid].stats;
        stats->last_mcs_rx = wil_rxdesc_mcs(d);
-       wil->stats.last_mcs_rx = stats->last_mcs_rx;
 
        /* use radiotap header only if required */
        if (ndev->type == ARPHRD_IEEE80211_RADIOTAP)
index bc5706a4f007b11eadd4b53faece30b45e49266f..a1ac4f87d47b0c9ad76da154963a1f6b71918f9a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 67e9624f7111b8842492d81d07665c5ec0973705..f8718fe547c4aca257f1831b5a2cf5ba129a20b1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -133,6 +133,9 @@ struct RGF_ICR {
 #define RGF_HP_CTRL                    (0x88265c)
 #define RGF_PCIE_LOS_COUNTER_CTL       (0x882dc4)
 
+/* MAC timer, usec, for packet lifetime */
+#define RGF_MAC_MTRL_COUNTER_0         (0x886aa8)
+
 /* popular locations */
 #define HOST_MBOX   HOSTADDR(RGF_USER_USER_SCRATCH_PAD)
 #define HOST_SW_INT (HOSTADDR(RGF_USER_USER_ICR) + \
@@ -327,17 +330,6 @@ struct wil_tid_ampdu_rx {
        bool first_time; /* is it 1-st time this buffer used? */
 };
 
-struct wil6210_stats {
-       u64 tsf;
-       u32 snr;
-       u16 last_mcs_rx;
-       u16 bf_mcs; /* last BF, used for Tx */
-       u16 my_rx_sector;
-       u16 my_tx_sector;
-       u16 peer_rx_sector;
-       u16 peer_tx_sector;
-};
-
 enum wil_sta_status {
        wil_sta_unused = 0,
        wil_sta_conn_pending = 1,
@@ -430,7 +422,6 @@ struct wil6210_priv {
 
        struct mutex mutex; /* for wil6210_priv access in wil_{up|down} */
        /* statistics */
-       struct wil6210_stats stats;
        atomic_t isr_count_rx, isr_count_tx;
        /* debugfs */
        struct dentry *debug;
index 1d1d0afdd2e195c6856372299e3fc635b213df23..b1aaaee997d515c92beb08e14ac8bcb611547cc6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -14,6 +14,7 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include <linux/moduleparam.h>
 #include <linux/etherdevice.h>
 #include <linux/if_arp.h>
 
 #include "wmi.h"
 #include "trace.h"
 
+static uint max_assoc_sta = 1;
+module_param(max_assoc_sta, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(max_assoc_sta, " Max number of stations associated to the AP");
+
 /**
  * WMI event receiving - theory of operations
  *
@@ -346,11 +351,11 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)
                                    rx_mgmt_frame->bssid);
                        cfg80211_put_bss(wiphy, bss);
                } else {
-                       wil_err(wil, "cfg80211_inform_bss() failed\n");
+                       wil_err(wil, "cfg80211_inform_bss_frame() failed\n");
                }
        } else {
                cfg80211_rx_mgmt(wil->wdev, freq, signal,
-                                (void *)rx_mgmt_frame, d_len, 0, GFP_KERNEL);
+                                (void *)rx_mgmt_frame, d_len, 0);
        }
 }
 
@@ -482,33 +487,6 @@ static void wmi_evt_disconnect(struct wil6210_priv *wil, int id,
        mutex_unlock(&wil->mutex);
 }
 
-static void wmi_evt_notify(struct wil6210_priv *wil, int id, void *d, int len)
-{
-       struct wmi_notify_req_done_event *evt = d;
-
-       if (len < sizeof(*evt)) {
-               wil_err(wil, "Short NOTIFY event\n");
-               return;
-       }
-
-       wil->stats.tsf = le64_to_cpu(evt->tsf);
-       wil->stats.snr = le32_to_cpu(evt->snr_val);
-       wil->stats.bf_mcs = le16_to_cpu(evt->bf_mcs);
-       wil->stats.my_rx_sector = le16_to_cpu(evt->my_rx_sector);
-       wil->stats.my_tx_sector = le16_to_cpu(evt->my_tx_sector);
-       wil->stats.peer_rx_sector = le16_to_cpu(evt->other_rx_sector);
-       wil->stats.peer_tx_sector = le16_to_cpu(evt->other_tx_sector);
-       wil_dbg_wmi(wil, "Link status, MCS %d TSF 0x%016llx\n"
-                   "BF status 0x%08x SNR 0x%08x SQI %d%%\n"
-                   "Tx Tpt %d goodput %d Rx goodput %d\n"
-                   "Sectors(rx:tx) my %d:%d peer %d:%d\n",
-                   wil->stats.bf_mcs, wil->stats.tsf, evt->status,
-                   wil->stats.snr, evt->sqi, le32_to_cpu(evt->tx_tpt),
-                   le32_to_cpu(evt->tx_goodput), le32_to_cpu(evt->rx_goodput),
-                   wil->stats.my_rx_sector, wil->stats.my_tx_sector,
-                   wil->stats.peer_rx_sector, wil->stats.peer_tx_sector);
-}
-
 /*
  * Firmware reports EAPOL frame using WME event.
  * Reconstruct Ethernet frame and deliver it via normal Rx
@@ -651,7 +629,6 @@ static const struct {
        {WMI_SCAN_COMPLETE_EVENTID,     wmi_evt_scan_complete},
        {WMI_CONNECT_EVENTID,           wmi_evt_connect},
        {WMI_DISCONNECT_EVENTID,        wmi_evt_disconnect},
-       {WMI_NOTIFY_REQ_DONE_EVENTID,   wmi_evt_notify},
        {WMI_EAPOL_RX_EVENTID,          wmi_evt_eapol_rx},
        {WMI_DATA_PORT_OPEN_EVENTID,    wmi_evt_linkup},
        {WMI_WBE_LINKDOWN_EVENTID,      wmi_evt_linkdown},
@@ -822,7 +799,7 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan)
                .network_type = wmi_nettype,
                .disable_sec_offload = 1,
                .channel = chan - 1,
-               .pcp_max_assoc_sta = WIL6210_MAX_CID,
+               .pcp_max_assoc_sta = max_assoc_sta,
        };
        struct {
                struct wil6210_mbox_hdr_wmi wmi;
@@ -832,6 +809,14 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan)
        if (!wil->secure_pcp)
                cmd.disable_sec = 1;
 
+       if ((cmd.pcp_max_assoc_sta > WIL6210_MAX_CID) ||
+           (cmd.pcp_max_assoc_sta <= 0)) {
+               wil_info(wil,
+                        "Requested connection limit %u, valid values are 1 - %d. Setting to %d\n",
+                        max_assoc_sta, WIL6210_MAX_CID, WIL6210_MAX_CID);
+               cmd.pcp_max_assoc_sta = WIL6210_MAX_CID;
+       }
+
        /*
         * Processing time may be huge, in case of secure AP it takes about
         * 3500ms for FW to start AP
index 17334c852866c3cc8a061eecb829052ebd9415cf..061618cee9f6685c5645c8dec98f3651ffdcd64a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
  * Copyright (c) 2006-2012 Wilocity .
  *
  * Permission to use, copy, modify, and/or distribute this software for any
@@ -980,7 +980,7 @@ struct wmi_ready_event {
  * WMI_NOTIFY_REQ_DONE_EVENTID
  */
 struct wmi_notify_req_done_event {
-       __le32 status;
+       __le32 status; /* beamforming status, 0: fail; 1: OK; 2: retrying */
        __le64 tsf;
        __le32 snr_val;
        __le32 tx_tpt;
index 4cfb4d99ced0c3ceb22c05814008d5d21250ef04..7afc9c5329fb1b307a83773cf19e3d9d1b2b3cba 100644 (file)
@@ -66,18 +66,18 @@ static void atmel_release(struct pcmcia_device *link);
 
 static void atmel_detach(struct pcmcia_device *p_dev);
 
-typedef struct local_info_t {
+struct local_info {
        struct net_device *eth_dev;
-} local_info_t;
+};
 
 static int atmel_probe(struct pcmcia_device *p_dev)
 {
-       local_info_t *local;
+       struct local_info *local;
 
        dev_dbg(&p_dev->dev, "atmel_attach()\n");
 
        /* Allocate space for private device-specific data */
-       local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
+       local = kzalloc(sizeof(*local), GFP_KERNEL);
        if (!local)
                return -ENOMEM;
 
@@ -117,7 +117,7 @@ static int atmel_config_check(struct pcmcia_device *p_dev, void *priv_data)
 
 static int atmel_config(struct pcmcia_device *link)
 {
-       local_info_t *dev;
+       struct local_info *dev;
        int ret;
        const struct pcmcia_device_id *did;
 
@@ -141,14 +141,14 @@ static int atmel_config(struct pcmcia_device *link)
        if (ret)
                goto failed;
 
-       ((local_info_t*)link->priv)->eth_dev =
+       ((struct local_info *)link->priv)->eth_dev =
                init_atmel_card(link->irq,
                                link->resource[0]->start,
                                did ? did->driver_info : ATMEL_FW_TYPE_NONE,
                                &link->dev,
                                card_present,
                                link);
-       if (!((local_info_t*)link->priv)->eth_dev)
+       if (!((struct local_info *)link->priv)->eth_dev)
                        goto failed;
 
 
@@ -161,20 +161,20 @@ static int atmel_config(struct pcmcia_device *link)
 
 static void atmel_release(struct pcmcia_device *link)
 {
-       struct net_device *dev = ((local_info_t*)link->priv)->eth_dev;
+       struct net_device *dev = ((struct local_info *)link->priv)->eth_dev;
 
        dev_dbg(&link->dev, "atmel_release\n");
 
        if (dev)
                stop_atmel_card(dev);
-       ((local_info_t*)link->priv)->eth_dev = NULL;
+       ((struct local_info *)link->priv)->eth_dev = NULL;
 
        pcmcia_disable_device(link);
 }
 
 static int atmel_suspend(struct pcmcia_device *link)
 {
-       local_info_t *local = link->priv;
+       struct local_info *local = link->priv;
 
        netif_device_detach(local->eth_dev);
 
@@ -183,7 +183,7 @@ static int atmel_suspend(struct pcmcia_device *link)
 
 static int atmel_resume(struct pcmcia_device *link)
 {
-       local_info_t *local = link->priv;
+       struct local_info *local = link->priv;
 
        atmel_open(local->eth_dev);
        netif_device_attach(local->eth_dev);
index 6e00b8804ada1f2a1274a5af33aef5540aa85ecc..9f7965aae93dc0b1d73de69f5c66c67ee0beb368 100644 (file)
@@ -18,6 +18,7 @@ b43-y                         += xmit.o
 b43-y                          += dma.o
 b43-y                          += pio.o
 b43-y                          += rfkill.o
+b43-y                          += ppr.o
 b43-$(CONFIG_B43_LEDS)         += leds.o
 b43-$(CONFIG_B43_PCMCIA)       += pcmcia.o
 b43-$(CONFIG_B43_SDIO)         += sdio.o
index 4113b69347640359aa22020eb0dcfd7efe0b7c14..95a9433264207b1be007a130d12f65d51fdcf2e2 100644 (file)
@@ -457,6 +457,7 @@ enum {
 #define B43_MACCTL_RADIOLOCK           0x00080000      /* Radio lock */
 #define B43_MACCTL_BEACPROMISC         0x00100000      /* Beacon Promiscuous */
 #define B43_MACCTL_KEEP_BADPLCP                0x00200000      /* Keep frames with bad PLCP */
+#define B43_MACCTL_PHY_LOCK            0x00200000
 #define B43_MACCTL_KEEP_CTL            0x00400000      /* Keep control frames */
 #define B43_MACCTL_KEEP_BAD            0x00800000      /* Keep bad frames (FCS) */
 #define B43_MACCTL_PROMISC             0x01000000      /* Promiscuous mode */
@@ -791,6 +792,13 @@ struct b43_firmware {
        bool pcm_request_failed;
 };
 
+enum b43_band {
+       B43_BAND_2G = 0,
+       B43_BAND_5G_LO = 1,
+       B43_BAND_5G_MI = 2,
+       B43_BAND_5G_HI = 3,
+};
+
 /* Device (802.11 core) initialization status. */
 enum {
        B43_STAT_UNINIT = 0,    /* Uninitialized. */
@@ -1012,6 +1020,16 @@ static inline void b43_write16(struct b43_wldev *dev, u16 offset, u16 value)
        dev->dev->write16(dev->dev, offset, value);
 }
 
+/* To optimize this check for flush_writes on BCM47XX_BCMA only. */
+static inline void b43_write16f(struct b43_wldev *dev, u16 offset, u16 value)
+{
+       b43_write16(dev, offset, value);
+#if defined(CONFIG_BCM47XX_BCMA)
+       if (dev->dev->flush_writes)
+               b43_read16(dev, offset);
+#endif
+}
+
 static inline void b43_maskset16(struct b43_wldev *dev, u16 offset, u16 mask,
                                 u16 set)
 {
index 565fdbdd6915f33e36cdbea616db209cf633bc4e..17d16a391fe6556dc66ab9a6bd5e4d0bd0c954a3 100644 (file)
 
 */
 
+#ifdef CONFIG_BCM47XX_BCMA
+#include <asm/mach-bcm47xx/bcm47xx.h>
+#endif
+
 #include "b43.h"
 #include "bus.h"
 
@@ -102,6 +106,12 @@ struct b43_bus_dev *b43_bus_dev_bcma_init(struct bcma_device *core)
        dev->write32 = b43_bus_bcma_write32;
        dev->block_read = b43_bus_bcma_block_read;
        dev->block_write = b43_bus_bcma_block_write;
+#ifdef CONFIG_BCM47XX_BCMA
+       if (b43_bus_host_is_pci(dev) &&
+           bcm47xx_bus_type == BCM47XX_BUS_TYPE_BCMA &&
+           bcm47xx_bus.bcma.bus.chipinfo.id == BCMA_CHIP_ID_BCM4716)
+               dev->flush_writes = true;
+#endif
 
        dev->dev = &core->dev;
        dev->dma_dev = core->dma_dev;
index f3205c6988bc4354a14a5226011f762868253936..256c2c17939afe7720a643bae1c32187a9850bc5 100644 (file)
@@ -33,6 +33,7 @@ struct b43_bus_dev {
                           size_t count, u16 offset, u8 reg_width);
        void (*block_write)(struct b43_bus_dev *dev, const void *buffer,
                            size_t count, u16 offset, u8 reg_width);
+       bool flush_writes;
 
        struct device *dev;
        struct device *dma_dev;
@@ -60,7 +61,21 @@ static inline bool b43_bus_host_is_pcmcia(struct b43_bus_dev *dev)
 #else
        return false;
 #endif
+};
+
+static inline bool b43_bus_host_is_pci(struct b43_bus_dev *dev)
+{
+#ifdef CONFIG_B43_BCMA
+       if (dev->bus_type == B43_BUS_BCMA)
+               return (dev->bdev->bus->hosttype == BCMA_HOSTTYPE_PCI);
+#endif
+#ifdef CONFIG_B43_SSB
+       if (dev->bus_type == B43_BUS_SSB)
+               return (dev->sdev->bus->bustype == SSB_BUSTYPE_PCI);
+#endif
+       return false;
 }
+
 static inline bool b43_bus_host_is_sdio(struct b43_bus_dev *dev)
 {
 #ifdef CONFIG_B43_SSB
index 2af1ac396eb451897371f6ff576f565843781e69..66ff718cc4129298d169e40300deeb3c8bb50583 100644 (file)
@@ -4466,10 +4466,10 @@ static int b43_phy_versioning(struct b43_wldev *dev)
        if (core_rev == 40 || core_rev == 42) {
                radio_manuf = 0x17F;
 
-               b43_write16(dev, B43_MMIO_RADIO24_CONTROL, 0);
+               b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, 0);
                radio_rev = b43_read16(dev, B43_MMIO_RADIO24_DATA);
 
-               b43_write16(dev, B43_MMIO_RADIO24_CONTROL, 1);
+               b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, 1);
                radio_id = b43_read16(dev, B43_MMIO_RADIO24_DATA);
 
                radio_ver = 0; /* Is there version somewhere? */
@@ -4477,7 +4477,7 @@ static int b43_phy_versioning(struct b43_wldev *dev)
                u16 radio24[3];
 
                for (tmp = 0; tmp < 3; tmp++) {
-                       b43_write16(dev, B43_MMIO_RADIO24_CONTROL, tmp);
+                       b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, tmp);
                        radio24[tmp] = b43_read16(dev, B43_MMIO_RADIO24_DATA);
                }
 
@@ -4494,13 +4494,12 @@ static int b43_phy_versioning(struct b43_wldev *dev)
                        else
                                tmp = 0x5205017F;
                } else {
-                       b43_write16(dev, B43_MMIO_RADIO_CONTROL,
-                                   B43_RADIOCTL_ID);
+                       b43_write16f(dev, B43_MMIO_RADIO_CONTROL,
+                                    B43_RADIOCTL_ID);
                        tmp = b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
-                       b43_write16(dev, B43_MMIO_RADIO_CONTROL,
-                                   B43_RADIOCTL_ID);
-                       tmp |= (u32)b43_read16(dev, B43_MMIO_RADIO_DATA_HIGH)
-                               << 16;
+                       b43_write16f(dev, B43_MMIO_RADIO_CONTROL,
+                                    B43_RADIOCTL_ID);
+                       tmp |= b43_read16(dev, B43_MMIO_RADIO_DATA_HIGH) << 16;
                }
                radio_manuf = (tmp & 0x00000FFF);
                radio_id = (tmp & 0x0FFFF000) >> 12;
index 25e40432d68b9c0c9dcc25ff44f2386b56e6ca68..99c036f5ecb7b51319d4c2b26d9b3719af028947 100644 (file)
@@ -444,14 +444,14 @@ static inline u16 adjust_phyreg(struct b43_wldev *dev, u16 offset)
 static u16 b43_aphy_op_read(struct b43_wldev *dev, u16 reg)
 {
        reg = adjust_phyreg(dev, reg);
-       b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+       b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
        return b43_read16(dev, B43_MMIO_PHY_DATA);
 }
 
 static void b43_aphy_op_write(struct b43_wldev *dev, u16 reg, u16 value)
 {
        reg = adjust_phyreg(dev, reg);
-       b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+       b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
        b43_write16(dev, B43_MMIO_PHY_DATA, value);
 }
 
index 3cbef21b4726dc106c5746f79689a10d0db6c4e0..1dfc682a805513f5e5d160f6198f6d17bec644fc 100644 (file)
@@ -222,12 +222,18 @@ static inline void assert_mac_suspended(struct b43_wldev *dev)
 u16 b43_radio_read(struct b43_wldev *dev, u16 reg)
 {
        assert_mac_suspended(dev);
+       dev->phy.writes_counter = 0;
        return dev->phy.ops->radio_read(dev, reg);
 }
 
 void b43_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
 {
        assert_mac_suspended(dev);
+       if (b43_bus_host_is_pci(dev->dev) &&
+           ++dev->phy.writes_counter > B43_MAX_WRITES_IN_ROW) {
+               b43_read32(dev, B43_MMIO_MACCTL);
+               dev->phy.writes_counter = 1;
+       }
        dev->phy.ops->radio_write(dev, reg, value);
 }
 
@@ -268,17 +274,28 @@ u16 b43_phy_read(struct b43_wldev *dev, u16 reg)
 {
        assert_mac_suspended(dev);
        dev->phy.writes_counter = 0;
-       return dev->phy.ops->phy_read(dev, reg);
+
+       if (dev->phy.ops->phy_read)
+               return dev->phy.ops->phy_read(dev, reg);
+
+       b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
+       return b43_read16(dev, B43_MMIO_PHY_DATA);
 }
 
 void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value)
 {
        assert_mac_suspended(dev);
-       dev->phy.ops->phy_write(dev, reg, value);
-       if (++dev->phy.writes_counter == B43_MAX_WRITES_IN_ROW) {
+       if (b43_bus_host_is_pci(dev->dev) &&
+           ++dev->phy.writes_counter > B43_MAX_WRITES_IN_ROW) {
                b43_read16(dev, B43_MMIO_PHY_VER);
-               dev->phy.writes_counter = 0;
+               dev->phy.writes_counter = 1;
        }
+
+       if (dev->phy.ops->phy_write)
+               return dev->phy.ops->phy_write(dev, reg, value);
+
+       b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
+       b43_write16(dev, B43_MMIO_PHY_DATA, value);
 }
 
 void b43_phy_copy(struct b43_wldev *dev, u16 destreg, u16 srcreg)
index 8f5c14bc10e6fedcab2d7b88a0009470772dad8a..727ce6edb4b3831faf6d254ad789b4a9a1a7c336 100644 (file)
@@ -2555,13 +2555,13 @@ static void b43_gphy_op_exit(struct b43_wldev *dev)
 
 static u16 b43_gphy_op_read(struct b43_wldev *dev, u16 reg)
 {
-       b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+       b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
        return b43_read16(dev, B43_MMIO_PHY_DATA);
 }
 
 static void b43_gphy_op_write(struct b43_wldev *dev, u16 reg, u16 value)
 {
-       b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+       b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
        b43_write16(dev, B43_MMIO_PHY_DATA, value);
 }
 
@@ -2572,7 +2572,7 @@ static u16 b43_gphy_op_radio_read(struct b43_wldev *dev, u16 reg)
        /* G-PHY needs 0x80 for read access. */
        reg |= 0x80;
 
-       b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
+       b43_write16f(dev, B43_MMIO_RADIO_CONTROL, reg);
        return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
 }
 
@@ -2581,7 +2581,7 @@ static void b43_gphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
        /* Register 1 is a 32-bit register. */
        B43_WARN_ON(reg == 1);
 
-       b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
+       b43_write16f(dev, B43_MMIO_RADIO_CONTROL, reg);
        b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value);
 }
 
index f2974c6b1c01fa3ddd11753a74badac91bc9b43e..c4dc8b020f604ed51d585a790d931ef2b668f350 100644 (file)
@@ -1071,22 +1071,10 @@ static unsigned int b43_phy_ht_op_get_default_chan(struct b43_wldev *dev)
  * R/W ops.
  **************************************************/
 
-static u16 b43_phy_ht_op_read(struct b43_wldev *dev, u16 reg)
-{
-       b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
-       return b43_read16(dev, B43_MMIO_PHY_DATA);
-}
-
-static void b43_phy_ht_op_write(struct b43_wldev *dev, u16 reg, u16 value)
-{
-       b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
-       b43_write16(dev, B43_MMIO_PHY_DATA, value);
-}
-
 static void b43_phy_ht_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask,
                                 u16 set)
 {
-       b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+       b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
        b43_write16(dev, B43_MMIO_PHY_DATA,
                    (b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set);
 }
@@ -1096,14 +1084,14 @@ static u16 b43_phy_ht_op_radio_read(struct b43_wldev *dev, u16 reg)
        /* HT-PHY needs 0x200 for read access */
        reg |= 0x200;
 
-       b43_write16(dev, B43_MMIO_RADIO24_CONTROL, reg);
+       b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, reg);
        return b43_read16(dev, B43_MMIO_RADIO24_DATA);
 }
 
 static void b43_phy_ht_op_radio_write(struct b43_wldev *dev, u16 reg,
                                      u16 value)
 {
-       b43_write16(dev, B43_MMIO_RADIO24_CONTROL, reg);
+       b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, reg);
        b43_write16(dev, B43_MMIO_RADIO24_DATA, value);
 }
 
@@ -1126,8 +1114,6 @@ const struct b43_phy_operations b43_phyops_ht = {
        .free                   = b43_phy_ht_op_free,
        .prepare_structs        = b43_phy_ht_op_prepare_structs,
        .init                   = b43_phy_ht_op_init,
-       .phy_read               = b43_phy_ht_op_read,
-       .phy_write              = b43_phy_ht_op_write,
        .phy_maskset            = b43_phy_ht_op_maskset,
        .radio_read             = b43_phy_ht_op_radio_read,
        .radio_write            = b43_phy_ht_op_radio_write,
index e76bbdf3247e9b095af94bf907b2439f3f25f5f3..97461ccf3e1e58ba4033b97756c0dd50491b13bf 100644 (file)
@@ -810,22 +810,10 @@ static void b43_phy_lcn_op_adjust_txpower(struct b43_wldev *dev)
  * R/W ops.
  **************************************************/
 
-static u16 b43_phy_lcn_op_read(struct b43_wldev *dev, u16 reg)
-{
-       b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
-       return b43_read16(dev, B43_MMIO_PHY_DATA);
-}
-
-static void b43_phy_lcn_op_write(struct b43_wldev *dev, u16 reg, u16 value)
-{
-       b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
-       b43_write16(dev, B43_MMIO_PHY_DATA, value);
-}
-
 static void b43_phy_lcn_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask,
                                   u16 set)
 {
-       b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+       b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
        b43_write16(dev, B43_MMIO_PHY_DATA,
                    (b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set);
 }
@@ -835,14 +823,14 @@ static u16 b43_phy_lcn_op_radio_read(struct b43_wldev *dev, u16 reg)
        /* LCN-PHY needs 0x200 for read access */
        reg |= 0x200;
 
-       b43_write16(dev, B43_MMIO_RADIO24_CONTROL, reg);
+       b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, reg);
        return b43_read16(dev, B43_MMIO_RADIO24_DATA);
 }
 
 static void b43_phy_lcn_op_radio_write(struct b43_wldev *dev, u16 reg,
                                       u16 value)
 {
-       b43_write16(dev, B43_MMIO_RADIO24_CONTROL, reg);
+       b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, reg);
        b43_write16(dev, B43_MMIO_RADIO24_DATA, value);
 }
 
@@ -855,8 +843,6 @@ const struct b43_phy_operations b43_phyops_lcn = {
        .free                   = b43_phy_lcn_op_free,
        .prepare_structs        = b43_phy_lcn_op_prepare_structs,
        .init                   = b43_phy_lcn_op_init,
-       .phy_read               = b43_phy_lcn_op_read,
-       .phy_write              = b43_phy_lcn_op_write,
        .phy_maskset            = b43_phy_lcn_op_maskset,
        .radio_read             = b43_phy_lcn_op_radio_read,
        .radio_write            = b43_phy_lcn_op_radio_write,
index 92190dacf6895c31cfbd9748930465e4dc5a4f59..058a9f2320503ef623748ed595ccbfdb8dbd9414 100644 (file)
@@ -1985,22 +1985,10 @@ static void lpphy_calibration(struct b43_wldev *dev)
        b43_mac_enable(dev);
 }
 
-static u16 b43_lpphy_op_read(struct b43_wldev *dev, u16 reg)
-{
-       b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
-       return b43_read16(dev, B43_MMIO_PHY_DATA);
-}
-
-static void b43_lpphy_op_write(struct b43_wldev *dev, u16 reg, u16 value)
-{
-       b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
-       b43_write16(dev, B43_MMIO_PHY_DATA, value);
-}
-
 static void b43_lpphy_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask,
                                 u16 set)
 {
-       b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+       b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
        b43_write16(dev, B43_MMIO_PHY_DATA,
                    (b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set);
 }
@@ -2016,7 +2004,7 @@ static u16 b43_lpphy_op_radio_read(struct b43_wldev *dev, u16 reg)
        } else
                reg |= 0x200;
 
-       b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
+       b43_write16f(dev, B43_MMIO_RADIO_CONTROL, reg);
        return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
 }
 
@@ -2025,7 +2013,7 @@ static void b43_lpphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
        /* Register 1 is a 32-bit register. */
        B43_WARN_ON(reg == 1);
 
-       b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
+       b43_write16f(dev, B43_MMIO_RADIO_CONTROL, reg);
        b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value);
 }
 
@@ -2713,8 +2701,6 @@ const struct b43_phy_operations b43_phyops_lp = {
        .free                   = b43_lpphy_op_free,
        .prepare_structs        = b43_lpphy_op_prepare_structs,
        .init                   = b43_lpphy_op_init,
-       .phy_read               = b43_lpphy_op_read,
-       .phy_write              = b43_lpphy_op_write,
        .phy_maskset            = b43_lpphy_op_maskset,
        .radio_read             = b43_lpphy_op_radio_read,
        .radio_write            = b43_lpphy_op_radio_write,
index e2a3f0d5bcc27cc5a2f960989ad866fb11a644b9..cf625d8732a7cdf3402b71494d6d53e3668bf4ab 100644 (file)
@@ -34,6 +34,7 @@
 #include "radio_2056.h"
 #include "radio_2057.h"
 #include "main.h"
+#include "ppr.h"
 
 struct nphy_txgains {
        u16 tx_lpf[2];
@@ -3606,16 +3607,6 @@ static void b43_nphy_iq_cal_gain_params(struct b43_wldev *dev, u16 core,
  * Tx and Rx
  **************************************************/
 
-static void b43_nphy_op_adjust_txpower(struct b43_wldev *dev)
-{//TODO
-}
-
-static enum b43_txpwr_result b43_nphy_op_recalc_txpower(struct b43_wldev *dev,
-                                                       bool ignore_tssi)
-{//TODO
-       return B43_TXPWR_RES_DONE;
-}
-
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlEnable */
 static void b43_nphy_tx_power_ctrl(struct b43_wldev *dev, bool enable)
 {
@@ -4069,6 +4060,7 @@ static void b43_nphy_tx_power_ctl_setup(struct b43_wldev *dev)
 
        s16 a1[2], b0[2], b1[2];
        u8 idle[2];
+       u8 ppr_max;
        s8 target[2];
        s32 num, den, pwr;
        u32 regval[64];
@@ -4147,7 +4139,12 @@ static void b43_nphy_tx_power_ctl_setup(struct b43_wldev *dev)
                        b1[0] = b1[1] = -1393;
                }
        }
-       /* target[0] = target[1] = nphy->tx_power_max; */
+
+       ppr_max = b43_ppr_get_max(dev, &nphy->tx_pwr_max_ppr);
+       if (ppr_max) {
+               target[0] = ppr_max;
+               target[1] = ppr_max;
+       }
 
        if (dev->phy.rev >= 3) {
                if (sprom->fem.ghz2.tssipos)
@@ -4235,8 +4232,9 @@ static void b43_nphy_tx_gain_table_upload(struct b43_wldev *dev)
 
        const u32 *table = NULL;
        u32 rfpwr_offset;
-       u8 pga_gain;
+       u8 pga_gain, pad_gain;
        int i;
+       const s16 *uninitialized_var(rf_pwr_offset_table);
 
        table = b43_nphy_get_tx_gain_table(dev);
        if (!table)
@@ -4252,13 +4250,27 @@ static void b43_nphy_tx_gain_table_upload(struct b43_wldev *dev)
        nphy->gmval = (table[0] >> 16) & 0x7000;
 #endif
 
+       if (phy->rev >= 19) {
+               return;
+       } else if (phy->rev >= 7) {
+               rf_pwr_offset_table = b43_ntab_get_rf_pwr_offset_table(dev);
+               if (!rf_pwr_offset_table)
+                       return;
+               /* TODO: Enable this once we have gains configured */
+               return;
+       }
+
        for (i = 0; i < 128; i++) {
                if (phy->rev >= 19) {
                        /* TODO */
                        return;
                } else if (phy->rev >= 7) {
-                       /* TODO */
-                       return;
+                       pga_gain = (table[i] >> 24) & 0xf;
+                       pad_gain = (table[i] >> 19) & 0x1f;
+                       if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+                               rfpwr_offset = rf_pwr_offset_table[pad_gain];
+                       else
+                               rfpwr_offset = rf_pwr_offset_table[pga_gain];
                } else {
                        pga_gain = (table[i] >> 24) & 0xF;
                        if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
@@ -5874,6 +5886,69 @@ static void b43_nphy_set_rx_core_state(struct b43_wldev *dev, u8 mask)
        b43_mac_enable(dev);
 }
 
+static enum b43_txpwr_result b43_nphy_op_recalc_txpower(struct b43_wldev *dev,
+                                                       bool ignore_tssi)
+{
+       struct b43_phy *phy = &dev->phy;
+       struct b43_phy_n *nphy = dev->phy.n;
+       struct ieee80211_channel *channel = dev->wl->hw->conf.chandef.chan;
+       struct b43_ppr *ppr = &nphy->tx_pwr_max_ppr;
+       u8 max; /* qdBm */
+       bool tx_pwr_state;
+
+       if (nphy->tx_pwr_last_recalc_freq == channel->center_freq &&
+           nphy->tx_pwr_last_recalc_limit == phy->desired_txpower)
+               return B43_TXPWR_RES_DONE;
+
+       /* Make sure we have a clean PPR */
+       b43_ppr_clear(dev, ppr);
+
+       /* HW limitations */
+       b43_ppr_load_max_from_sprom(dev, ppr, B43_BAND_2G);
+
+       /* Regulatory & user settings */
+       max = INT_TO_Q52(phy->chandef->chan->max_power);
+       if (phy->desired_txpower)
+               max = min_t(u8, max, INT_TO_Q52(phy->desired_txpower));
+       b43_ppr_apply_max(dev, ppr, max);
+       if (b43_debug(dev, B43_DBG_XMITPOWER))
+               b43dbg(dev->wl, "Calculated TX power: " Q52_FMT "\n",
+                      Q52_ARG(b43_ppr_get_max(dev, ppr)));
+
+       /* TODO: Enable this once we get gains working */
+#if 0
+       /* Some extra gains */
+       hw_gain = 6; /* N-PHY specific */
+       if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+               hw_gain += sprom->antenna_gain.a0;
+       else
+               hw_gain += sprom->antenna_gain.a1;
+       b43_ppr_add(dev, ppr, -hw_gain);
+#endif
+
+       /* Make sure we didn't go too low */
+       b43_ppr_apply_min(dev, ppr, INT_TO_Q52(8));
+
+       /* Apply */
+       tx_pwr_state = nphy->txpwrctrl;
+       b43_mac_suspend(dev);
+       b43_nphy_tx_power_ctl_setup(dev);
+       if (dev->dev->core_rev == 11 || dev->dev->core_rev == 12) {
+               b43_maskset32(dev, B43_MMIO_MACCTL, ~0, B43_MACCTL_PHY_LOCK);
+               b43_read32(dev, B43_MMIO_MACCTL);
+               udelay(1);
+       }
+       b43_nphy_tx_power_ctrl(dev, nphy->txpwrctrl);
+       if (dev->dev->core_rev == 11 || dev->dev->core_rev == 12)
+               b43_maskset32(dev, B43_MMIO_MACCTL, ~B43_MACCTL_PHY_LOCK, 0);
+       b43_mac_enable(dev);
+
+       nphy->tx_pwr_last_recalc_freq = channel->center_freq;
+       nphy->tx_pwr_last_recalc_limit = phy->desired_txpower;
+
+       return B43_TXPWR_RES_DONE;
+}
+
 /**************************************************
  * N-PHY init
  **************************************************/
@@ -6407,6 +6482,7 @@ static int b43_nphy_op_allocate(struct b43_wldev *dev)
        nphy = kzalloc(sizeof(*nphy), GFP_KERNEL);
        if (!nphy)
                return -ENOMEM;
+
        dev->phy.n = nphy;
 
        return 0;
@@ -6497,26 +6573,13 @@ static inline void check_phyreg(struct b43_wldev *dev, u16 offset)
 #endif /* B43_DEBUG */
 }
 
-static u16 b43_nphy_op_read(struct b43_wldev *dev, u16 reg)
-{
-       check_phyreg(dev, reg);
-       b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
-       return b43_read16(dev, B43_MMIO_PHY_DATA);
-}
-
-static void b43_nphy_op_write(struct b43_wldev *dev, u16 reg, u16 value)
-{
-       check_phyreg(dev, reg);
-       b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
-       b43_write16(dev, B43_MMIO_PHY_DATA, value);
-}
-
 static void b43_nphy_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask,
                                 u16 set)
 {
        check_phyreg(dev, reg);
-       b43_write16(dev, B43_MMIO_PHY_CONTROL, reg);
+       b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
        b43_maskset16(dev, B43_MMIO_PHY_DATA, mask, set);
+       dev->phy.writes_counter = 1;
 }
 
 static u16 b43_nphy_op_radio_read(struct b43_wldev *dev, u16 reg)
@@ -6529,7 +6592,7 @@ static u16 b43_nphy_op_radio_read(struct b43_wldev *dev, u16 reg)
        else
                reg |= 0x100;
 
-       b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
+       b43_write16f(dev, B43_MMIO_RADIO_CONTROL, reg);
        return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
 }
 
@@ -6538,7 +6601,7 @@ static void b43_nphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
        /* Register 1 is a 32-bit register. */
        B43_WARN_ON(dev->phy.rev < 7 && reg == 1);
 
-       b43_write16(dev, B43_MMIO_RADIO_CONTROL, reg);
+       b43_write16f(dev, B43_MMIO_RADIO_CONTROL, reg);
        b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value);
 }
 
@@ -6652,8 +6715,6 @@ const struct b43_phy_operations b43_phyops_n = {
        .free                   = b43_nphy_op_free,
        .prepare_structs        = b43_nphy_op_prepare_structs,
        .init                   = b43_nphy_op_init,
-       .phy_read               = b43_nphy_op_read,
-       .phy_write              = b43_nphy_op_write,
        .phy_maskset            = b43_nphy_op_maskset,
        .radio_read             = b43_nphy_op_radio_read,
        .radio_write            = b43_nphy_op_radio_write,
@@ -6662,5 +6723,4 @@ const struct b43_phy_operations b43_phyops_n = {
        .switch_channel         = b43_nphy_op_switch_channel,
        .get_default_chan       = b43_nphy_op_get_default_chan,
        .recalc_txpower         = b43_nphy_op_recalc_txpower,
-       .adjust_txpower         = b43_nphy_op_adjust_txpower,
 };
index 30bec815b969651ee4ad1cca2c6c74e607cc834f..a6da2c31a99cf7c2dcc646b674eb2b35d6133ef8 100644 (file)
@@ -2,6 +2,7 @@
 #define B43_NPHY_H_
 
 #include "phy_common.h"
+#include "ppr.h"
 
 
 /* N-PHY registers. */
@@ -967,6 +968,9 @@ struct b43_phy_n {
        struct b43_phy_n_txpwrindex txpwrindex[2];
        struct b43_phy_n_pwr_ctl_info pwr_ctl_info[2];
        struct b43_chanspec txiqlocal_chanspec;
+       struct b43_ppr tx_pwr_max_ppr;
+       u16 tx_pwr_last_recalc_freq;
+       int tx_pwr_last_recalc_limit;
 
        u8 txrx_chain;
        u16 tx_rx_cal_phy_saveregs[11];
diff --git a/drivers/net/wireless/b43/ppr.c b/drivers/net/wireless/b43/ppr.c
new file mode 100644 (file)
index 0000000..9a77027
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * Broadcom B43 wireless driver
+ * PPR (Power Per Rate) management
+ *
+ * Copyright (c) 2014 RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include "ppr.h"
+#include "b43.h"
+
+#define ppr_for_each_entry(ppr, i, entry)                              \
+       for (i = 0, entry = &(ppr)->__all_rates[i];                     \
+            i < B43_PPR_RATES_NUM;                                     \
+            i++, entry++)
+
+void b43_ppr_clear(struct b43_wldev *dev, struct b43_ppr *ppr)
+{
+       memset(ppr, 0, sizeof(*ppr));
+
+       /* Compile-time PPR check */
+       BUILD_BUG_ON(sizeof(struct b43_ppr) != B43_PPR_RATES_NUM * sizeof(u8));
+}
+
+void b43_ppr_add(struct b43_wldev *dev, struct b43_ppr *ppr, int diff)
+{
+       int i;
+       u8 *rate;
+
+       ppr_for_each_entry(ppr, i, rate) {
+               *rate = clamp_val(*rate + diff, 0, 127);
+       }
+}
+
+void b43_ppr_apply_max(struct b43_wldev *dev, struct b43_ppr *ppr, u8 max)
+{
+       int i;
+       u8 *rate;
+
+       ppr_for_each_entry(ppr, i, rate) {
+               *rate = min(*rate, max);
+       }
+}
+
+void b43_ppr_apply_min(struct b43_wldev *dev, struct b43_ppr *ppr, u8 min)
+{
+       int i;
+       u8 *rate;
+
+       ppr_for_each_entry(ppr, i, rate) {
+               *rate = max(*rate, min);
+       }
+}
+
+u8 b43_ppr_get_max(struct b43_wldev *dev, struct b43_ppr *ppr)
+{
+       u8 res = 0;
+       int i;
+       u8 *rate;
+
+       ppr_for_each_entry(ppr, i, rate) {
+               res = max(*rate, res);
+       }
+
+       return res;
+}
+
+bool b43_ppr_load_max_from_sprom(struct b43_wldev *dev, struct b43_ppr *ppr,
+                                enum b43_band band)
+{
+       struct b43_ppr_rates *rates = &ppr->rates;
+       struct ssb_sprom *sprom = dev->dev->bus_sprom;
+       struct b43_phy *phy = &dev->phy;
+       u8 maxpwr, off;
+       u32 sprom_ofdm_po;
+       u16 *sprom_mcs_po;
+       u8 extra_cdd_po, extra_stbc_po;
+       int i;
+
+       switch (band) {
+       case B43_BAND_2G:
+               maxpwr = min(sprom->core_pwr_info[0].maxpwr_2g,
+                            sprom->core_pwr_info[1].maxpwr_2g);
+               sprom_ofdm_po = sprom->ofdm2gpo;
+               sprom_mcs_po = sprom->mcs2gpo;
+               extra_cdd_po = (sprom->cddpo >> 0) & 0xf;
+               extra_stbc_po = (sprom->stbcpo >> 0) & 0xf;
+               break;
+       case B43_BAND_5G_LO:
+               maxpwr = min(sprom->core_pwr_info[0].maxpwr_5gl,
+                            sprom->core_pwr_info[1].maxpwr_5gl);
+               sprom_ofdm_po = sprom->ofdm5glpo;
+               sprom_mcs_po = sprom->mcs5glpo;
+               extra_cdd_po = (sprom->cddpo >> 8) & 0xf;
+               extra_stbc_po = (sprom->stbcpo >> 8) & 0xf;
+               break;
+       case B43_BAND_5G_MI:
+               maxpwr = min(sprom->core_pwr_info[0].maxpwr_5g,
+                            sprom->core_pwr_info[1].maxpwr_5g);
+               sprom_ofdm_po = sprom->ofdm5gpo;
+               sprom_mcs_po = sprom->mcs5gpo;
+               extra_cdd_po = (sprom->cddpo >> 4) & 0xf;
+               extra_stbc_po = (sprom->stbcpo >> 4) & 0xf;
+               break;
+       case B43_BAND_5G_HI:
+               maxpwr = min(sprom->core_pwr_info[0].maxpwr_5gh,
+                            sprom->core_pwr_info[1].maxpwr_5gh);
+               sprom_ofdm_po = sprom->ofdm5ghpo;
+               sprom_mcs_po = sprom->mcs5ghpo;
+               extra_cdd_po = (sprom->cddpo >> 12) & 0xf;
+               extra_stbc_po = (sprom->stbcpo >> 12) & 0xf;
+               break;
+       default:
+               WARN_ON_ONCE(1);
+               return false;
+       }
+
+       if (band == B43_BAND_2G) {
+               for (i = 0; i < 4; i++) {
+                       off = ((sprom->cck2gpo >> (i * 4)) & 0xf) * 2;
+                       rates->cck[i] = maxpwr - off;
+               }
+       }
+
+       /* OFDM */
+       for (i = 0; i < 8; i++) {
+               off = ((sprom_ofdm_po >> (i * 4)) & 0xf) * 2;
+               rates->ofdm[i] = maxpwr - off;
+       }
+
+       /* MCS 20 SISO */
+       rates->mcs_20[0] = rates->ofdm[0];
+       rates->mcs_20[1] = rates->ofdm[2];
+       rates->mcs_20[2] = rates->ofdm[3];
+       rates->mcs_20[3] = rates->ofdm[4];
+       rates->mcs_20[4] = rates->ofdm[5];
+       rates->mcs_20[5] = rates->ofdm[6];
+       rates->mcs_20[6] = rates->ofdm[7];
+       rates->mcs_20[7] = rates->ofdm[7];
+
+       /* MCS 20 CDD */
+       for (i = 0; i < 4; i++) {
+               off = ((sprom_mcs_po[0] >> (i * 4)) & 0xf) * 2;
+               rates->mcs_20_cdd[i] = maxpwr - off;
+               if (phy->type == B43_PHYTYPE_N && phy->rev >= 3)
+                       rates->mcs_20_cdd[i] -= extra_cdd_po;
+       }
+       for (i = 0; i < 4; i++) {
+               off = ((sprom_mcs_po[1] >> (i * 4)) & 0xf) * 2;
+               rates->mcs_20_cdd[4 + i] = maxpwr - off;
+               if (phy->type == B43_PHYTYPE_N && phy->rev >= 3)
+                       rates->mcs_20_cdd[4 + i] -= extra_cdd_po;
+       }
+
+       /* OFDM 20 CDD */
+       rates->ofdm_20_cdd[0] = rates->mcs_20_cdd[0];
+       rates->ofdm_20_cdd[1] = rates->mcs_20_cdd[0];
+       rates->ofdm_20_cdd[2] = rates->mcs_20_cdd[1];
+       rates->ofdm_20_cdd[3] = rates->mcs_20_cdd[2];
+       rates->ofdm_20_cdd[4] = rates->mcs_20_cdd[3];
+       rates->ofdm_20_cdd[5] = rates->mcs_20_cdd[4];
+       rates->ofdm_20_cdd[6] = rates->mcs_20_cdd[5];
+       rates->ofdm_20_cdd[7] = rates->mcs_20_cdd[6];
+
+       /* MCS 20 STBC */
+       for (i = 0; i < 4; i++) {
+               off = ((sprom_mcs_po[0] >> (i * 4)) & 0xf) * 2;
+               rates->mcs_20_stbc[i] = maxpwr - off;
+               if (phy->type == B43_PHYTYPE_N && phy->rev >= 3)
+                       rates->mcs_20_stbc[i] -= extra_stbc_po;
+       }
+       for (i = 0; i < 4; i++) {
+               off = ((sprom_mcs_po[1] >> (i * 4)) & 0xf) * 2;
+               rates->mcs_20_stbc[4 + i] = maxpwr - off;
+               if (phy->type == B43_PHYTYPE_N && phy->rev >= 3)
+                       rates->mcs_20_stbc[4 + i] -= extra_stbc_po;
+       }
+
+       /* MCS 20 SDM */
+       for (i = 0; i < 4; i++) {
+               off = ((sprom_mcs_po[2] >> (i * 4)) & 0xf) * 2;
+               rates->mcs_20_sdm[i] = maxpwr - off;
+       }
+       for (i = 0; i < 4; i++) {
+               off = ((sprom_mcs_po[3] >> (i * 4)) & 0xf) * 2;
+               rates->mcs_20_sdm[4 + i] = maxpwr - off;
+       }
+
+       return true;
+}
diff --git a/drivers/net/wireless/b43/ppr.h b/drivers/net/wireless/b43/ppr.h
new file mode 100644 (file)
index 0000000..24d7447
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef LINUX_B43_PPR_H_
+#define LINUX_B43_PPR_H_
+
+#include <linux/types.h>
+
+#define B43_PPR_CCK_RATES_NUM          4
+#define B43_PPR_OFDM_RATES_NUM         8
+#define B43_PPR_MCS_RATES_NUM          8
+
+#define B43_PPR_RATES_NUM      (B43_PPR_CCK_RATES_NUM +        \
+                                B43_PPR_OFDM_RATES_NUM * 2 +   \
+                                B43_PPR_MCS_RATES_NUM * 4)
+
+struct b43_ppr_rates {
+       u8 cck[B43_PPR_CCK_RATES_NUM];
+       u8 ofdm[B43_PPR_OFDM_RATES_NUM];
+       u8 ofdm_20_cdd[B43_PPR_OFDM_RATES_NUM];
+       u8 mcs_20[B43_PPR_MCS_RATES_NUM]; /* SISO */
+       u8 mcs_20_cdd[B43_PPR_MCS_RATES_NUM];
+       u8 mcs_20_stbc[B43_PPR_MCS_RATES_NUM];
+       u8 mcs_20_sdm[B43_PPR_MCS_RATES_NUM];
+};
+
+struct b43_ppr {
+       /* All powers are in qdbm (Q5.2) */
+       union {
+               u8 __all_rates[B43_PPR_RATES_NUM];
+               struct b43_ppr_rates rates;
+       };
+};
+
+struct b43_wldev;
+enum b43_band;
+
+void b43_ppr_clear(struct b43_wldev *dev, struct b43_ppr *ppr);
+
+void b43_ppr_add(struct b43_wldev *dev, struct b43_ppr *ppr, int diff);
+void b43_ppr_apply_max(struct b43_wldev *dev, struct b43_ppr *ppr, u8 max);
+void b43_ppr_apply_min(struct b43_wldev *dev, struct b43_ppr *ppr, u8 min);
+u8 b43_ppr_get_max(struct b43_wldev *dev, struct b43_ppr *ppr);
+
+bool b43_ppr_load_max_from_sprom(struct b43_wldev *dev, struct b43_ppr *ppr,
+                                enum b43_band band);
+
+#endif /* LINUX_B43_PPR_H_ */
index 4b5885077b01bd5b223a3d45868adfc52a744882..25d1cbd34306e03ea4827e09509c345d11b5a1df 100644 (file)
@@ -2878,6 +2878,40 @@ const s8 b43_ntab_papd_pga_gain_delta_ipa_2g[] = {
        -54, -46, -39, -31, -23, -15, -8, 0
 };
 
+/* Extracted from MMIO dump of 6.30.223.248
+ * Entries: 0, 15, 17, 21, 24, 26, 27, 29, 30 were guessed
+ */
+static const s16 b43_ntab_rf_pwr_offset_2057_rev9_2g[] = {
+       -133, -133, -107, -92, -81,
+       -73, -66, -61, -56, -52,
+       -48, -44, -41, -37, -34,
+       -31, -28, -25, -22, -19,
+       -17, -14, -12, -10, -9,
+       -7, -5, -4, -3, -2,
+       -1, 0,
+};
+
+/* Extracted from MMIO dump of 6.30.223.248 */
+static const s16 b43_ntab_rf_pwr_offset_2057_rev9_5g[] = {
+       -101, -94, -86, -79, -72,
+       -65, -57, -50, -42, -35,
+       -28, -21, -16, -9, -4,
+       0,
+};
+
+/* Extracted from MMIO dump of 6.30.223.248
+ * Entries: 0, 26, 28, 29, 30, 31 were guessed
+ */
+static const s16 b43_ntab_rf_pwr_offset_2057_rev14_2g[] = {
+       -111, -111, -111, -84, -70,
+       -59, -52, -45, -40, -36,
+       -32, -29, -26, -23, -21,
+       -18, -16, -15, -13, -11,
+       -10, -8, -7, -6, -5,
+       -4, -4, -3, -3, -2,
+       -2, -1,
+};
+
 const u16 tbl_iqcal_gainparams[2][9][8] = {
        {
                { 0x000, 0, 0, 2, 0x69, 0x69, 0x69, 0x69 },
@@ -3197,7 +3231,7 @@ static struct nphy_gain_ctl_workaround_entry nphy_gain_ctl_workaround[2][4] = {
                        { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
                        0x527E, /* invalid for external LNA! */
                        { 0x513F, 0x513F, 0x513F, 0x513F }, /* invalid for external LNA! */
-                       0x1076, 0x0066, 0x0000, /* low is invalid (the last one) */
+                       0x007E, 0x0066, 0x0000, /* low is invalid (the last one) */
                        0x18, 0x18, 0x18,
                        0x01D0, 0x5,
                },
@@ -3708,9 +3742,43 @@ const u32 *b43_nphy_get_tx_gain_table(struct b43_wldev *dev)
        }
 }
 
+const s16 *b43_ntab_get_rf_pwr_offset_table(struct b43_wldev *dev)
+{
+       struct b43_phy *phy = &dev->phy;
+
+       if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+               switch (phy->rev) {
+               case 17:
+                       if (phy->radio_rev == 14)
+                               return b43_ntab_rf_pwr_offset_2057_rev14_2g;
+                       break;
+               case 16:
+                       if (phy->radio_rev == 9)
+                               return b43_ntab_rf_pwr_offset_2057_rev9_2g;
+                       break;
+               }
+
+               b43err(dev->wl,
+                      "No 2GHz RF power table available for this device\n");
+               return NULL;
+       } else {
+               switch (phy->rev) {
+               case 16:
+                       if (phy->radio_rev == 9)
+                               return b43_ntab_rf_pwr_offset_2057_rev9_5g;
+                       break;
+               }
+
+               b43err(dev->wl,
+                      "No 5GHz RF power table available for this device\n");
+               return NULL;
+       }
+}
+
 struct nphy_gain_ctl_workaround_entry *b43_nphy_get_gain_ctl_workaround_ent(
        struct b43_wldev *dev, bool ghz5, bool ext_lna)
 {
+       struct b43_phy *phy = &dev->phy;
        struct nphy_gain_ctl_workaround_entry *e;
        u8 phy_idx;
 
@@ -3729,37 +3797,49 @@ struct nphy_gain_ctl_workaround_entry *b43_nphy_get_gain_ctl_workaround_ent(
        e = &nphy_gain_ctl_workaround[ghz5][phy_idx];
 
        /* Some workarounds to the workarounds... */
-       if (ghz5 && dev->phy.rev >= 6) {
-               if (dev->phy.radio_rev == 11 &&
-                   !b43_is_40mhz(dev))
-                       e->cliplo_gain = 0x2d;
-       } else if (!ghz5 && dev->phy.rev >= 5) {
-               static const int gain_data[] = {0x0062, 0x0064, 0x006a, 0x106a,
-                                               0x106c, 0x1074, 0x107c, 0x207c};
+       if (!ghz5) {
                u8 tr_iso = dev->dev->bus_sprom->fem.ghz2.tr_iso;
 
-               if (ext_lna) {
+               if (tr_iso > 7)
+                       tr_iso = 3;
+
+               if (phy->rev >= 6) {
+                       static const int gain_data[] = { 0x106a, 0x106c, 0x1074,
+                                                        0x107c, 0x007e, 0x107e,
+                                                        0x207e, 0x307e, };
+
+                       e->cliplo_gain = gain_data[tr_iso];
+               } else if (phy->rev == 5) {
+                       static const int gain_data[] = { 0x0062, 0x0064, 0x006a,
+                                                        0x106a, 0x106c, 0x1074,
+                                                        0x107c, 0x207c, };
+
+                       e->cliplo_gain = gain_data[tr_iso];
+               }
+
+               if (phy->rev >= 5 && ext_lna) {
                        e->rfseq_init[0] &= ~0x4000;
                        e->rfseq_init[1] &= ~0x4000;
                        e->rfseq_init[2] &= ~0x4000;
                        e->rfseq_init[3] &= ~0x4000;
                        e->init_gain &= ~0x4000;
                }
-               if (tr_iso > 7)
-                       tr_iso = 3;
-               e->cliplo_gain = gain_data[tr_iso];
-
-       } else if (ghz5 && dev->phy.rev == 4 && ext_lna) {
-               e->rfseq_init[0] &= ~0x4000;
-               e->rfseq_init[1] &= ~0x4000;
-               e->rfseq_init[2] &= ~0x4000;
-               e->rfseq_init[3] &= ~0x4000;
-               e->init_gain &= ~0x4000;
-               e->rfseq_init[0] |= 0x1000;
-               e->rfseq_init[1] |= 0x1000;
-               e->rfseq_init[2] |= 0x1000;
-               e->rfseq_init[3] |= 0x1000;
-               e->init_gain |= 0x1000;
+       } else {
+               if (phy->rev >= 6) {
+                       if (phy->radio_rev == 11 && !b43_is_40mhz(dev))
+                               e->crsminu = 0x2d;
+               } else if (phy->rev == 4 && ext_lna) {
+                       e->rfseq_init[0] &= ~0x4000;
+                       e->rfseq_init[1] &= ~0x4000;
+                       e->rfseq_init[2] &= ~0x4000;
+                       e->rfseq_init[3] &= ~0x4000;
+                       e->init_gain &= ~0x4000;
+                       e->rfseq_init[0] |= 0x1000;
+                       e->rfseq_init[1] |= 0x1000;
+                       e->rfseq_init[2] |= 0x1000;
+                       e->rfseq_init[3] |= 0x1000;
+                       e->init_gain |= 0x1000;
+               }
        }
 
        return e;
index 3ce2e6f3a2781d168cf0955f6246b24a1d5d1181..b51f386db02fa8faf40a98481110b251d2295fe7 100644 (file)
@@ -191,6 +191,8 @@ void b43_nphy_tables_init(struct b43_wldev *dev);
 
 const u32 *b43_nphy_get_tx_gain_table(struct b43_wldev *dev);
 
+const s16 *b43_ntab_get_rf_pwr_offset_table(struct b43_wldev *dev);
+
 extern const s8 b43_ntab_papd_pga_gain_delta_ipa_2g[];
 
 extern const u16 tbl_iqcal_gainparams[2][9][8];
index 057b982ea8b37f90792fc53ca9337a9f13897e32..1d78a91db59428a137bb829cbd3203bac69fea36 100644 (file)
@@ -1431,8 +1431,7 @@ int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp,
                                              IEEE80211_BAND_5GHZ);
 
        wdev = &ifp->vif->wdev;
-       cfg80211_rx_mgmt(wdev, freq, 0, (u8 *)mgmt_frame, mgmt_frame_len, 0,
-                        GFP_ATOMIC);
+       cfg80211_rx_mgmt(wdev, freq, 0, (u8 *)mgmt_frame, mgmt_frame_len, 0);
 
        kfree(mgmt_frame);
        return 0;
@@ -1896,8 +1895,7 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp,
                                              IEEE80211_BAND_2GHZ :
                                              IEEE80211_BAND_5GHZ);
 
-       cfg80211_rx_mgmt(&vif->wdev, freq, 0, mgmt_frame, mgmt_frame_len, 0,
-                        GFP_ATOMIC);
+       cfg80211_rx_mgmt(&vif->wdev, freq, 0, mgmt_frame, mgmt_frame_len, 0);
 
        brcmf_dbg(INFO, "mgmt_frame_len (%d) , e->datalen (%d), chanspec (%04x), freq (%d)\n",
                  mgmt_frame_len, e->datalen, chanspec, freq);
index 02fe706fc9ec8cbeed88baacc377c33e6892dd6d..12a60ca1462a24106fe2da3b9629b3ab91201ccb 100644 (file)
@@ -2394,9 +2394,13 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg,
        brcmf_dbg(CONN, "Beacon interval: %d\n", notify_interval);
        brcmf_dbg(CONN, "Signal: %d\n", notify_signal);
 
-       bss = cfg80211_inform_bss(wiphy, notify_channel, (const u8 *)bi->BSSID,
-               0, notify_capability, notify_interval, notify_ie,
-               notify_ielen, notify_signal, GFP_KERNEL);
+       bss = cfg80211_inform_bss(wiphy, notify_channel,
+                                 CFG80211_BSS_FTYPE_UNKNOWN,
+                                 (const u8 *)bi->BSSID,
+                                 0, notify_capability,
+                                 notify_interval, notify_ie,
+                                 notify_ielen, notify_signal,
+                                 GFP_KERNEL);
 
        if (!bss)
                return -ENOMEM;
@@ -2498,9 +2502,11 @@ static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg,
        brcmf_dbg(CONN, "beacon interval: %d\n", notify_interval);
        brcmf_dbg(CONN, "signal: %d\n", notify_signal);
 
-       bss = cfg80211_inform_bss(wiphy, notify_channel, bssid,
-               0, notify_capability, notify_interval,
-               notify_ie, notify_ielen, notify_signal, GFP_KERNEL);
+       bss = cfg80211_inform_bss(wiphy, notify_channel,
+                                 CFG80211_BSS_FTYPE_UNKNOWN, bssid, 0,
+                                 notify_capability, notify_interval,
+                                 notify_ie, notify_ielen, notify_signal,
+                                 GFP_KERNEL);
 
        if (!bss) {
                err = -ENOMEM;
index 40078f5f932ec6b1ea3a26af5453f2bc5d2206ec..964b64ab7fe3a10aed8024f79abe6a23df6afb38 100644 (file)
@@ -398,7 +398,7 @@ static int cw1200_spi_probe(struct spi_device *func)
                return -1;
        }
 
-       self = kzalloc(sizeof(*self), GFP_KERNEL);
+       self = devm_kzalloc(&func->dev, sizeof(*self), GFP_KERNEL);
        if (!self) {
                pr_err("Can't allocate SPI hwbus_priv.");
                return -ENOMEM;
@@ -424,7 +424,6 @@ static int cw1200_spi_probe(struct spi_device *func)
        if (status) {
                cw1200_spi_irq_unsubscribe(self);
                cw1200_spi_off(plat_data);
-               kfree(self);
        }
 
        return status;
@@ -441,7 +440,6 @@ static int cw1200_spi_disconnect(struct spi_device *func)
                        cw1200_core_release(self->core);
                        self->core = NULL;
                }
-               kfree(self);
        }
        cw1200_spi_off(dev_get_platdata(&func->dev));
 
index a42f9c335090697297165bd6d15d8b6c5594a855..f0c3c77a48d38eb7e2318280ab9492582091c39f 100644 (file)
@@ -5552,7 +5552,7 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
                            min(network->ssid_len, priv->essid_len)))) {
                        char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
 
-                       strncpy(escaped,
+                       strlcpy(escaped,
                                print_ssid(ssid, network->ssid,
                                           network->ssid_len),
                                sizeof(escaped));
@@ -5765,7 +5765,7 @@ static int ipw_best_network(struct ipw_priv *priv,
                     memcmp(network->ssid, priv->essid,
                            min(network->ssid_len, priv->essid_len)))) {
                        char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
-                       strncpy(escaped,
+                       strlcpy(escaped,
                                print_ssid(ssid, network->ssid,
                                           network->ssid_len),
                                sizeof(escaped));
@@ -5782,7 +5782,7 @@ static int ipw_best_network(struct ipw_priv *priv,
         * testing everything else. */
        if (match->network && match->network->stats.rssi > network->stats.rssi) {
                char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
-               strncpy(escaped,
+               strlcpy(escaped,
                        print_ssid(ssid, network->ssid, network->ssid_len),
                        sizeof(escaped));
                IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded because "
index 6451d2b6abcff3c33f486c9d7eb90390647a1266..267e48a2915e7885993979337619d777c8cb74c8 100644 (file)
@@ -51,7 +51,6 @@ config IWLWIFI_LEDS
 
 config IWLDVM
        tristate "Intel Wireless WiFi DVM Firmware support"
-       depends on m
        default IWLWIFI
        help
          This is the driver that supports the DVM firmware which is
@@ -60,7 +59,6 @@ config IWLDVM
 
 config IWLMVM
        tristate "Intel Wireless WiFi MVM Firmware support"
-       depends on m
        help
          This is the driver that supports the MVM firmware which is
          currently only available for 7260 and 3160 devices.
@@ -87,6 +85,16 @@ config IWLWIFI_BCAST_FILTERING
          If unsure, don't enable this option, as some programs might
          expect incoming broadcasts for their normal operations.
 
+config IWLWIFI_UAPSD
+       bool "enable U-APSD by default"
+       depends on IWLMVM
+       help
+         Say Y here to enable U-APSD by default. This may cause
+         interoperability problems with some APs, manifesting in lower than
+         expected throughput due to those APs not enabling aggregation
+
+         If unsure, say N.
+
 menu "Debugging Options"
 
 config IWLWIFI_DEBUG
index 6dc5dd3ced44723943934f114c6fde78c98a565f..ed50de6362ed1d5dcd56b45243ff0b140dcbafe5 100644 (file)
@@ -1068,6 +1068,13 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
        /* recalculate basic rates */
        iwl_calc_basic_rates(priv, ctx);
 
+       /*
+        * force CTS-to-self frames protection if RTS-CTS is not preferred
+        * one aggregation protection method
+        */
+       if (!priv->hw_params.use_rts_for_aggregation)
+               ctx->staging.flags |= RXON_FLG_SELF_CTS_EN;
+
        if ((ctx->vif && ctx->vif->bss_conf.use_short_slot) ||
            !(ctx->staging.flags & RXON_FLG_BAND_24G_MSK))
                ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
@@ -1473,6 +1480,11 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
        else
                ctx->staging.flags &= ~RXON_FLG_TGG_PROTECT_MSK;
 
+       if (bss_conf->use_cts_prot)
+               ctx->staging.flags |= RXON_FLG_SELF_CTS_EN;
+       else
+               ctx->staging.flags &= ~RXON_FLG_SELF_CTS_EN;
+
        memcpy(ctx->staging.bssid_addr, bss_conf->bssid, ETH_ALEN);
 
        if (vif->type == NL80211_IFTYPE_AP ||
index 3255a1723d176f59ee5547e7981a9d3bbe7d9583..d1ce3ce13591717099db5b83571334db75efd0fb 100644 (file)
@@ -580,7 +580,7 @@ turn_off:
                 * time, or we hadn't time to drain the AC queues.
                 */
                if (agg_state == IWL_AGG_ON)
-                       iwl_trans_txq_disable(priv->trans, txq_id);
+                       iwl_trans_txq_disable(priv->trans, txq_id, true);
                else
                        IWL_DEBUG_TX_QUEUES(priv, "Don't disable tx agg: %d\n",
                                            agg_state);
@@ -686,7 +686,7 @@ int iwlagn_tx_agg_flush(struct iwl_priv *priv, struct ieee80211_vif *vif,
                 * time, or we hadn't time to drain the AC queues.
                 */
                if (agg_state == IWL_AGG_ON)
-                       iwl_trans_txq_disable(priv->trans, txq_id);
+                       iwl_trans_txq_disable(priv->trans, txq_id, true);
                else
                        IWL_DEBUG_TX_QUEUES(priv, "Don't disable tx agg: %d\n",
                                            agg_state);
@@ -781,7 +781,7 @@ static void iwlagn_check_ratid_empty(struct iwl_priv *priv, int sta_id, u8 tid)
                                "Can continue DELBA flow ssn = next_recl = %d\n",
                                tid_data->next_reclaimed);
                        iwl_trans_txq_disable(priv->trans,
-                                             tid_data->agg.txq_id);
+                                             tid_data->agg.txq_id, true);
                        iwlagn_dealloc_agg_txq(priv, tid_data->agg.txq_id);
                        tid_data->agg.state = IWL_AGG_OFF;
                        ieee80211_stop_tx_ba_cb_irqsafe(vif, addr, tid);
index 48730064da73f5e1e058f756d9473a2a0a5bc376..7e26d0dbfcf7a191933df3e0a5468560dc2fd587 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -67,8 +69,8 @@
 #include "iwl-agn-hw.h"
 
 /* Highest firmware API version supported */
-#define IWL7260_UCODE_API_MAX  9
-#define IWL3160_UCODE_API_MAX  9
+#define IWL7260_UCODE_API_MAX  10
+#define IWL3160_UCODE_API_MAX  10
 
 /* Oldest version we won't warn about */
 #define IWL7260_UCODE_API_OK   9
index 44b19e015102096e39fd086539794ab608c4c359..23a67bfc086f3e35c774d4027d9b9b8f3c35b273 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -67,7 +69,7 @@
 #include "iwl-agn-hw.h"
 
 /* Highest firmware API version supported */
-#define IWL8000_UCODE_API_MAX  9
+#define IWL8000_UCODE_API_MAX  10
 
 /* Oldest version we won't warn about */
 #define IWL8000_UCODE_API_OK   8
index fe129c94ae3ea52e068d5cdc7f7e15732c033d4e..23d059af647693138e691121f95075600582d4f1 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 295083510e729a76f13347a568c661acbdfdda52..0a70bcd241f5b9703096726e9e3e81b1cb84b5f0 100644 (file)
@@ -145,6 +145,7 @@ do {                                                                \
 #define IWL_DL_HCMD            0x00000004
 #define IWL_DL_STATE           0x00000008
 /* 0x000000F0 - 0x00000010 */
+#define IWL_DL_QUOTA           0x00000010
 #define IWL_DL_TE              0x00000020
 #define IWL_DL_EEPROM          0x00000040
 #define IWL_DL_RADIO           0x00000080
@@ -189,6 +190,7 @@ do {                                                                \
 #define IWL_DEBUG_LED(p, f, a...)      IWL_DEBUG(p, IWL_DL_LED, f, ## a)
 #define IWL_DEBUG_WEP(p, f, a...)      IWL_DEBUG(p, IWL_DL_WEP, f, ## a)
 #define IWL_DEBUG_HC(p, f, a...)       IWL_DEBUG(p, IWL_DL_HCMD, f, ## a)
+#define IWL_DEBUG_QUOTA(p, f, a...)    IWL_DEBUG(p, IWL_DL_QUOTA, f, ## a)
 #define IWL_DEBUG_TE(p, f, a...)       IWL_DEBUG(p, IWL_DL_TE, f, ## a)
 #define IWL_DEBUG_EEPROM(d, f, a...)   IWL_DEBUG_DEV(d, IWL_DL_EEPROM, f, ## a)
 #define IWL_DEBUG_CALIB(p, f, a...)    IWL_DEBUG(p, IWL_DL_CALIB, f, ## a)
index 23e7351e02decaa49026b8f628c67990f1607d2a..90987d6f348e8f253bf2611edc5e82768401efdf 100644 (file)
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite8);
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ioread32);
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite32);
-EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_rx);
-EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_tx);
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_event);
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_error);
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_cont_event);
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_wrap_event);
-EXPORT_TRACEPOINT_SYMBOL(iwlwifi_info);
-EXPORT_TRACEPOINT_SYMBOL(iwlwifi_warn);
-EXPORT_TRACEPOINT_SYMBOL(iwlwifi_crit);
-EXPORT_TRACEPOINT_SYMBOL(iwlwifi_err);
-EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dbg);
 #endif
index 77e3178040b2a80716ff97cb3c4771b356682897..aefd94cb6e91e30ecdd2d8b4808d3cc39bdc50b7 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -1254,7 +1256,9 @@ struct iwl_mod_params iwlwifi_mod_params = {
        .bt_coex_active = true,
        .power_level = IWL_POWER_INDEX_1,
        .wd_disable = true,
-       .uapsd_disable = false,
+#ifndef CONFIG_IWLWIFI_UAPSD
+       .uapsd_disable = true,
+#endif /* CONFIG_IWLWIFI_UAPSD */
        /* the rest are 0 by default */
 };
 IWL_EXPORT_SYMBOL(iwlwifi_mod_params);
@@ -1370,7 +1374,11 @@ MODULE_PARM_DESC(nvm_file, "NVM file name");
 
 module_param_named(uapsd_disable, iwlwifi_mod_params.uapsd_disable,
                   bool, S_IRUGO);
+#ifdef CONFIG_IWLWIFI_UAPSD
 MODULE_PARM_DESC(uapsd_disable, "disable U-APSD functionality (default: N)");
+#else
+MODULE_PARM_DESC(uapsd_disable, "disable U-APSD functionality (default: Y)");
+#endif
 
 /*
  * set bt_coex_active to true, uCode will do kill/defer
index 3c72cb710b0cb8dc4b4d7d7be478488acc569029..be4f8972241a9bf59324848746172bb3c57150c1 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index de5994a776c765a99c66bc86e0533451d4c7a027..e30a41d04c8b3ac1af8878ab1d72fc02419aa80a 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 929a8063354ca43e456b9f46fbc9d4e51c22a8a1..401f7be36b934b7524d56508c579e663212c8782 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 1bb5193c5b1b5097c11bbf5a986f4c4d6e409c58..f68cba4e04440e869ff5e69f431ad82365cb23d4 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -125,6 +127,8 @@ enum iwl_ucode_tlv_flag {
  * @IWL_UCODE_TLV_API_CSA_FLOW: ucode can do unbind-bind flow for CSA.
  * @IWL_UCODE_TLV_API_DISABLE_STA_TX: ucode supports tx_disable bit.
  * @IWL_UCODE_TLV_API_LMAC_SCAN: This ucode uses LMAC unified scan API.
+ * @IWL_UCODE_TLV_API_FRAGMENTED_SCAN: This ucode supports active dwell time
+ *     longer than the passive one, which is essential for fragmented scan.
  */
 enum iwl_ucode_tlv_api {
        IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID     = BIT(0),
@@ -133,6 +137,7 @@ enum iwl_ucode_tlv_api {
        IWL_UCODE_TLV_API_CSA_FLOW              = BIT(4),
        IWL_UCODE_TLV_API_DISABLE_STA_TX        = BIT(5),
        IWL_UCODE_TLV_API_LMAC_SCAN             = BIT(6),
+       IWL_UCODE_TLV_API_FRAGMENTED_SCAN       = BIT(8),
 };
 
 /**
index 018af2957d3b7b319c47222eae4d1dfe1cdc3891..8e7af798abd13b3a8e31f861b4892a40922ce608 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 99785c892f963c7435b0048c4a097f6cae9e7808..b6d666ee8359df46c5052135fd7ddcfb82525868 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 47033a35a40293f100312ede34bfc3a5b43c9efd..1560f4576c7d3ce69e7373f5fdb688a0243f2cb1 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #define SCD_CHAINEXT_EN                (SCD_BASE + 0x244)
 #define SCD_AGGR_SEL           (SCD_BASE + 0x248)
 #define SCD_INTERRUPT_MASK     (SCD_BASE + 0x108)
+#define SCD_EN_CTRL            (SCD_BASE + 0x254)
 
 static inline unsigned int SCD_QUEUE_WRPTR(unsigned int chnl)
 {
diff --git a/drivers/net/wireless/iwlwifi/iwl-scd.h b/drivers/net/wireless/iwlwifi/iwl-scd.h
new file mode 100644 (file)
index 0000000..6c622b2
--- /dev/null
@@ -0,0 +1,118 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2014 Intel Mobile Communications GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called COPYING.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Intel Mobile Communications GmbH
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation 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 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 __iwl_scd_h__
+#define __iwl_scd_h__
+
+#include "iwl-trans.h"
+#include "iwl-io.h"
+#include "iwl-prph.h"
+
+
+static inline void iwl_scd_txq_set_inactive(struct iwl_trans *trans,
+                                           u16 txq_id)
+{
+       iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id),
+                      (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)|
+                      (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
+}
+
+static inline void iwl_scd_txq_set_chain(struct iwl_trans *trans,
+                                        u16 txq_id)
+{
+       iwl_set_bits_prph(trans, SCD_QUEUECHAIN_SEL, BIT(txq_id));
+}
+
+static inline void iwl_scd_txq_enable_agg(struct iwl_trans *trans,
+                                         u16 txq_id)
+{
+       iwl_set_bits_prph(trans, SCD_AGGR_SEL, BIT(txq_id));
+}
+
+static inline void iwl_scd_txq_disable_agg(struct iwl_trans *trans,
+                                          u16 txq_id)
+{
+       iwl_clear_bits_prph(trans, SCD_AGGR_SEL, BIT(txq_id));
+}
+
+static inline void iwl_scd_disable_agg(struct iwl_trans *trans)
+{
+       iwl_set_bits_prph(trans, SCD_AGGR_SEL, 0);
+}
+
+static inline void iwl_scd_activate_fifos(struct iwl_trans *trans)
+{
+       iwl_write_prph(trans, SCD_TXFACT, IWL_MASK(0, 7));
+}
+
+static inline void iwl_scd_deactivate_fifos(struct iwl_trans *trans)
+{
+       iwl_write_prph(trans, SCD_TXFACT, 0);
+}
+
+static inline void iwl_scd_enable_set_active(struct iwl_trans *trans,
+                                            u32 value)
+{
+       iwl_write_prph(trans, SCD_EN_CTRL, value);
+}
+#endif
index 656371a668daa5e2325e45fe0b576fc3e13bd307..c89985a58803cb6aa33f55c89c91b32f63acf4a7 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -401,6 +403,14 @@ struct iwl_trans_dump_data {
 
 struct iwl_trans;
 
+struct iwl_trans_txq_scd_cfg {
+       u8 fifo;
+       s8 sta_id;
+       u8 tid;
+       bool aggregate;
+       int frame_limit;
+};
+
 /**
  * struct iwl_trans_ops - transport specific operations
  *
@@ -437,7 +447,9 @@ struct iwl_trans;
  *     Must be atomic
  * @txq_enable: setup a queue. To setup an AC queue, use the
  *     iwl_trans_ac_txq_enable wrapper. fw_alive must have been called before
- *     this one. The op_mode must not configure the HCMD queue. May sleep.
+ *     this one. The op_mode must not configure the HCMD queue. The scheduler
+ *     configuration may be %NULL, in which case the hardware will not be
+ *     configured. May sleep.
  * @txq_disable: de-configure a Tx queue to send AMPDUs
  *     Must be atomic
  * @wait_tx_queue_empty: wait until tx queues are empty. May sleep.
@@ -492,9 +504,10 @@ struct iwl_trans_ops {
        void (*reclaim)(struct iwl_trans *trans, int queue, int ssn,
                        struct sk_buff_head *skbs);
 
-       void (*txq_enable)(struct iwl_trans *trans, int queue, int fifo,
-                          int sta_id, int tid, int frame_limit, u16 ssn);
-       void (*txq_disable)(struct iwl_trans *trans, int queue);
+       void (*txq_enable)(struct iwl_trans *trans, int queue, u16 ssn,
+                          const struct iwl_trans_txq_scd_cfg *cfg);
+       void (*txq_disable)(struct iwl_trans *trans, int queue,
+                           bool configure_scd);
 
        int (*dbgfs_register)(struct iwl_trans *trans, struct dentry* dir);
        int (*wait_tx_queue_empty)(struct iwl_trans *trans, u32 txq_bm);
@@ -766,29 +779,57 @@ static inline void iwl_trans_reclaim(struct iwl_trans *trans, int queue,
        trans->ops->reclaim(trans, queue, ssn, skbs);
 }
 
-static inline void iwl_trans_txq_disable(struct iwl_trans *trans, int queue)
+static inline void iwl_trans_txq_disable(struct iwl_trans *trans, int queue,
+                                        bool configure_scd)
 {
-       trans->ops->txq_disable(trans, queue);
+       trans->ops->txq_disable(trans, queue, configure_scd);
 }
 
-static inline void iwl_trans_txq_enable(struct iwl_trans *trans, int queue,
-                                       int fifo, int sta_id, int tid,
-                                       int frame_limit, u16 ssn)
+static inline void
+iwl_trans_txq_enable_cfg(struct iwl_trans *trans, int queue, u16 ssn,
+                        const struct iwl_trans_txq_scd_cfg *cfg)
 {
        might_sleep();
 
        if (unlikely((trans->state != IWL_TRANS_FW_ALIVE)))
                IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state);
 
-       trans->ops->txq_enable(trans, queue, fifo, sta_id, tid,
-                                frame_limit, ssn);
+       trans->ops->txq_enable(trans, queue, ssn, cfg);
+}
+
+static inline void iwl_trans_txq_enable(struct iwl_trans *trans, int queue,
+                                       int fifo, int sta_id, int tid,
+                                       int frame_limit, u16 ssn)
+{
+       struct iwl_trans_txq_scd_cfg cfg = {
+               .fifo = fifo,
+               .sta_id = sta_id,
+               .tid = tid,
+               .frame_limit = frame_limit,
+               .aggregate = sta_id >= 0,
+       };
+
+       iwl_trans_txq_enable_cfg(trans, queue, ssn, &cfg);
 }
 
 static inline void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue,
                                           int fifo)
 {
-       iwl_trans_txq_enable(trans, queue, fifo, -1,
-                            IWL_MAX_TID_COUNT, IWL_FRAME_LIMIT, 0);
+       struct iwl_trans_txq_scd_cfg cfg = {
+               .fifo = fifo,
+               .sta_id = -1,
+               .tid = IWL_MAX_TID_COUNT,
+               .frame_limit = IWL_FRAME_LIMIT,
+               .aggregate = false,
+       };
+
+       iwl_trans_txq_enable_cfg(trans, queue, 0, &cfg);
+}
+
+static inline void
+iwl_trans_txq_enable_no_scd(struct iwl_trans *trans, int queue, u16 ssn)
+{
+       iwl_trans_txq_enable_cfg(trans, queue, ssn, NULL);
 }
 
 static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans,
index 2291bbcaaeab8bfe57c3aa20f9409bab41ba4cef..2262d6dc61aea41548aa57f4eb707e0e4e1b9697 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index a3be3335992766348a670028d3bfa7f2a390ea60..585c0ab4a3ec5fc59ca8d2e84395c74b27b4fcd2 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index ca79f7160573445110485b313d9a31a871d990b2..dd00e8f7f76553294f7a4774d3fb070964d12f5c 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 645b3cfc29a5e5c0bcb10f6c9eaded6a1827e5ed..c17be0fb7283a4f51c570002d1fc7c743d354daa 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -700,7 +702,7 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
                return ret;
        rcu_assign_pointer(mvm->fw_id_to_mac_id[mvmvif->ap_sta_id], ap_sta);
 
-       ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false);
+       ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
        if (ret)
                return ret;
 
index 2e90ff795c13212d6d8ca7be35df935a907d6b3c..d919b4ebc83ccdb6c0adc0912b7edbbbc2e5b86b 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -119,6 +121,10 @@ static void iwl_dbgfs_update_pm(struct iwl_mvm *mvm,
                IWL_DEBUG_POWER(mvm, "uapsd_misbehaving_enable=%d\n", val);
                dbgfs_pm->uapsd_misbehaving = val;
                break;
+       case MVM_DEBUGFS_PM_USE_PS_POLL:
+               IWL_DEBUG_POWER(mvm, "use_ps_poll=%d\n", val);
+               dbgfs_pm->use_ps_poll = val;
+               break;
        }
 }
 
@@ -169,6 +175,10 @@ static ssize_t iwl_dbgfs_pm_params_write(struct ieee80211_vif *vif, char *buf,
                if (sscanf(buf + 18, "%d", &val) != 1)
                        return -EINVAL;
                param = MVM_DEBUGFS_PM_UAPSD_MISBEHAVING;
+       } else if (!strncmp("use_ps_poll=", buf, 12)) {
+               if (sscanf(buf + 12, "%d", &val) != 1)
+                       return -EINVAL;
+               param = MVM_DEBUGFS_PM_USE_PS_POLL;
        } else {
                return -EINVAL;
        }
index 7d18f466fbb3351b3b173fdcf4aa15bddd5d0b75..d98ee109c5e93c6e6be08c51bed17548e810a013 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -257,6 +259,70 @@ static ssize_t iwl_dbgfs_sram_write(struct iwl_mvm *mvm, char *buf,
        return count;
 }
 
+static ssize_t iwl_dbgfs_set_nic_temperature_read(struct file *file,
+                                                 char __user *user_buf,
+                                                 size_t count, loff_t *ppos)
+{
+       struct iwl_mvm *mvm = file->private_data;
+       char buf[16];
+       int pos;
+
+       if (!mvm->temperature_test)
+               pos = scnprintf(buf , sizeof(buf), "disabled\n");
+       else
+               pos = scnprintf(buf , sizeof(buf), "%d\n", mvm->temperature);
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+/*
+ * Set NIC Temperature
+ * Cause the driver to ignore the actual NIC temperature reported by the FW
+ * Enable: any value between IWL_MVM_DEBUG_SET_TEMPERATURE_MIN -
+ * IWL_MVM_DEBUG_SET_TEMPERATURE_MAX
+ * Disable: IWL_MVM_DEBUG_SET_TEMPERATURE_DISABLE
+ */
+static ssize_t iwl_dbgfs_set_nic_temperature_write(struct iwl_mvm *mvm,
+                                                  char *buf, size_t count,
+                                                  loff_t *ppos)
+{
+       int temperature;
+
+       if (kstrtoint(buf, 10, &temperature))
+               return -EINVAL;
+       /* not a legal temperature */
+       if ((temperature > IWL_MVM_DEBUG_SET_TEMPERATURE_MAX &&
+            temperature != IWL_MVM_DEBUG_SET_TEMPERATURE_DISABLE) ||
+           temperature < IWL_MVM_DEBUG_SET_TEMPERATURE_MIN)
+               return -EINVAL;
+
+       mutex_lock(&mvm->mutex);
+       if (temperature == IWL_MVM_DEBUG_SET_TEMPERATURE_DISABLE) {
+               if (!mvm->temperature_test)
+                       goto out;
+
+               mvm->temperature_test = false;
+               /* Since we can't read the temp while awake, just set
+                * it to zero until we get the next RX stats from the
+                * firmware.
+                */
+               mvm->temperature = 0;
+       } else {
+               mvm->temperature_test = true;
+               mvm->temperature = temperature;
+       }
+       IWL_DEBUG_TEMP(mvm, "%sabling debug set temperature (temp = %d)\n",
+                      mvm->temperature_test ? "En" : "Dis" ,
+                      mvm->temperature);
+       /* handle the temperature change */
+       iwl_mvm_tt_handler(mvm);
+
+out:
+       mutex_unlock(&mvm->mutex);
+
+       return count;
+}
+
 static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
                                       size_t count, loff_t *ppos)
 {
@@ -1296,6 +1362,7 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(prph_reg, 64);
 MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush, 16);
 MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain, 8);
 MVM_DEBUGFS_READ_WRITE_FILE_OPS(sram, 64);
+MVM_DEBUGFS_READ_WRITE_FILE_OPS(set_nic_temperature, 64);
 MVM_DEBUGFS_READ_FILE_OPS(stations);
 MVM_DEBUGFS_READ_FILE_OPS(bt_notif);
 MVM_DEBUGFS_READ_FILE_OPS(bt_cmd);
@@ -1336,6 +1403,8 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
        MVM_DEBUGFS_ADD_FILE(tx_flush, mvm->debugfs_dir, S_IWUSR);
        MVM_DEBUGFS_ADD_FILE(sta_drain, mvm->debugfs_dir, S_IWUSR);
        MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, S_IWUSR | S_IRUSR);
+       MVM_DEBUGFS_ADD_FILE(set_nic_temperature, mvm->debugfs_dir,
+                            S_IWUSR | S_IRUSR);
        MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR);
        MVM_DEBUGFS_ADD_FILE(fw_error_dump, dbgfs_dir, S_IRUSR);
        MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR);
@@ -1380,6 +1449,13 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
                goto err;
 #endif
 
+       if (!debugfs_create_u8("low_latency_agg_frame_limit", S_IRUSR | S_IWUSR,
+                              mvm->debugfs_dir,
+                              &mvm->low_latency_agg_frame_limit))
+               goto err;
+       if (!debugfs_create_u8("ps_disabled", S_IRUSR,
+                              mvm->debugfs_dir, &mvm->ps_disabled))
+               goto err;
        if (!debugfs_create_blob("nvm_hw", S_IRUSR,
                                  mvm->debugfs_dir, &mvm->nvm_hw_blob))
                goto err;
index e3a9774af495d3ac814f24e923d10e124afbf2ca..8c4190e7e027e1b82319127bc333c82a384a3d80 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 69875716dcdb80abeb688949d826267eb391ccf0..816883f9ff94f541906cb945d0bf8002f8f3770b 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 13696fe419b778c68c9d72d7a289a3dd3c453b39..e74cdf2132f87a5a94ec2ff9f0c588b709833f24 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index c3a8c86b550d45aaca72a274252960d8397d0ef6..27dd86395b39dd0f5800efe9c73a52294a2099ed 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index c02a9e45ec5eaec78ce9ef49c47957c6fcd2c7da..8f2216694004caf290aa5414cefc4725260e0a26 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 47bd0406355d2738f00477d237c57bcd3d2706f2..21dd5b771660f0f689798b650fbb4acd1eed3d21 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 95f5b3274efb516f280eee74eb8f9649c51d599a..9c975f9ecfcb02609a9aca92af1f8ede4624e78b 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #include "fw-api-coex.h"
 #include "fw-api-scan.h"
 
-/* maximal number of Tx queues in any platform */
-#define IWL_MVM_MAX_QUEUES     20
-
 /* Tx queue numbers */
 enum {
        IWL_MVM_OFFCHANNEL_QUEUE = 8,
        IWL_MVM_CMD_QUEUE = 9,
 };
 
-#define IWL_MVM_CMD_FIFO       7
+enum iwl_mvm_tx_fifo {
+       IWL_MVM_TX_FIFO_BK = 0,
+       IWL_MVM_TX_FIFO_BE,
+       IWL_MVM_TX_FIFO_VI,
+       IWL_MVM_TX_FIFO_VO,
+       IWL_MVM_TX_FIFO_MCAST = 5,
+       IWL_MVM_TX_FIFO_CMD = 7,
+};
 
 #define IWL_MVM_STATION_COUNT  16
 
@@ -184,6 +190,8 @@ enum {
        REPLY_RX_MPDU_CMD = 0xc1,
        BA_NOTIF = 0xc5,
 
+       MARKER_CMD = 0xcb,
+
        /* BT Coex */
        BT_COEX_PRIO_TABLE = 0xcc,
        BT_COEX_PROT_ENV = 0xcd,
@@ -1307,6 +1315,38 @@ struct iwl_bcast_filter_cmd {
        struct iwl_fw_bcast_mac macs[NUM_MAC_INDEX_DRIVER];
 } __packed; /* BCAST_FILTERING_HCMD_API_S_VER_1 */
 
+/*
+ * enum iwl_mvm_marker_id - maker ids
+ *
+ * The ids for different type of markers to insert into the usniffer logs
+ */
+enum iwl_mvm_marker_id {
+       MARKER_ID_TX_FRAME_LATENCY = 1,
+}; /* MARKER_ID_API_E_VER_1 */
+
+/**
+ * struct iwl_mvm_marker - mark info into the usniffer logs
+ *
+ * (MARKER_CMD = 0xcb)
+ *
+ * Mark the UTC time stamp into the usniffer logs together with additional
+ * metadata, so the usniffer output can be parsed.
+ * In the command response the ucode will return the GP2 time.
+ *
+ * @dw_len: The amount of dwords following this byte including this byte.
+ * @marker_id: A unique marker id (iwl_mvm_marker_id).
+ * @reserved: reserved.
+ * @timestamp: in milliseconds since 1970-01-01 00:00:00 UTC
+ * @metadata: additional meta data that will be written to the unsiffer log
+ */
+struct iwl_mvm_marker {
+       u8 dwLen;
+       u8 markerId;
+       __le16 reserved;
+       __le64 timestamp;
+       __le32 metadata[0];
+} __packed; /* MARKER_API_S_VER_1 */
+
 struct mvm_statistics_dbg {
        __le32 burst_check;
        __le32 burst_count;
index 883e702152d5289163f48f7464cf630f6795ec2f..21d606028ca6a534528186e7c77103b7b7073b5d 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -242,10 +244,10 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
                        mvm->queue_to_mac80211[i] = i;
                else
                        mvm->queue_to_mac80211[i] = IWL_INVALID_MAC80211_QUEUE;
-               atomic_set(&mvm->queue_stop_count[i], 0);
        }
 
-       mvm->transport_queue_stop = 0;
+       for (i = 0; i < IEEE80211_MAX_QUEUES; i++)
+               atomic_set(&mvm->mac80211_queue_stop_count[i], 0);
 
        mvm->ucode_loaded = true;
 
index 0e523e28cabfc15b8beb63af3659cdc20d30b401..9cbb192f680e017fe98765aecdde64fcb8337d82 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -81,7 +83,7 @@ struct iwl_mvm_mac_iface_iterator_data {
        struct ieee80211_vif *vif;
        unsigned long available_mac_ids[BITS_TO_LONGS(NUM_MAC_INDEX_DRIVER)];
        unsigned long available_tsf_ids[BITS_TO_LONGS(NUM_TSF_IDS)];
-       unsigned long used_hw_queues[BITS_TO_LONGS(IWL_MVM_MAX_QUEUES)];
+       u32 used_hw_queues;
        enum iwl_tsf_id preferred_tsf;
        bool found_vif;
 };
@@ -192,12 +194,31 @@ static void iwl_mvm_mac_tsf_id_iter(void *_data, u8 *mac,
                data->preferred_tsf = NUM_TSF_IDS;
 }
 
+/*
+ * Get the mask of the queues used by the vif
+ */
+u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm,
+                               struct ieee80211_vif *vif)
+{
+       u32 qmask = 0, ac;
+
+       if (vif->type == NL80211_IFTYPE_P2P_DEVICE)
+               return BIT(IWL_MVM_OFFCHANNEL_QUEUE);
+
+       for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
+               qmask |= BIT(vif->hw_queue[ac]);
+
+       if (vif->type == NL80211_IFTYPE_AP)
+               qmask |= BIT(vif->cab_queue);
+
+       return qmask;
+}
+
 static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac,
                                       struct ieee80211_vif *vif)
 {
        struct iwl_mvm_mac_iface_iterator_data *data = _data;
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
-       u32 ac;
 
        /* Iterator may already find the interface being added -- skip it */
        if (vif == data->vif) {
@@ -206,12 +227,7 @@ static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac,
        }
 
        /* Mark the queues used by the vif */
-       for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
-               if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE)
-                       __set_bit(vif->hw_queue[ac], data->used_hw_queues);
-
-       if (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE)
-               __set_bit(vif->cab_queue, data->used_hw_queues);
+       data->used_hw_queues |= iwl_mvm_mac_get_queues_mask(data->mvm, vif);
 
        /* Mark MAC IDs as used by clearing the available bit, and
         * (below) mark TSFs as used if their existing use is not
@@ -225,24 +241,6 @@ static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac,
        iwl_mvm_mac_tsf_id_iter(_data, mac, vif);
 }
 
-/*
- * Get the mask of the queus used by the vif
- */
-u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm,
-                               struct ieee80211_vif *vif)
-{
-       u32 qmask = 0, ac;
-
-       if (vif->type == NL80211_IFTYPE_P2P_DEVICE)
-               return BIT(IWL_MVM_OFFCHANNEL_QUEUE);
-
-       for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
-               if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE)
-                       qmask |= BIT(vif->hw_queue[ac]);
-
-       return qmask;
-}
-
 void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm,
                                    struct ieee80211_vif *vif)
 {
@@ -277,15 +275,15 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm,
                .available_tsf_ids = { (1 << NUM_TSF_IDS) - 1 },
                /* no preference yet */
                .preferred_tsf = NUM_TSF_IDS,
-               .used_hw_queues = {
+               .used_hw_queues =
                        BIT(IWL_MVM_OFFCHANNEL_QUEUE) |
                        BIT(mvm->aux_queue) |
-                       BIT(IWL_MVM_CMD_QUEUE)
-               },
+                       BIT(IWL_MVM_CMD_QUEUE),
                .found_vif = false,
        };
        u32 ac;
        int ret, i;
+       unsigned long used_hw_queues;
 
        /*
         * Allocate a MAC ID and a TSF for this MAC, along with the queues
@@ -368,9 +366,11 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm,
                return 0;
        }
 
+       used_hw_queues = data.used_hw_queues;
+
        /* Find available queues, and allocate them to the ACs */
        for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
-               u8 queue = find_first_zero_bit(data.used_hw_queues,
+               u8 queue = find_first_zero_bit(&used_hw_queues,
                                               mvm->first_agg_queue);
 
                if (queue >= mvm->first_agg_queue) {
@@ -379,13 +379,13 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm,
                        goto exit_fail;
                }
 
-               __set_bit(queue, data.used_hw_queues);
+               __set_bit(queue, &used_hw_queues);
                vif->hw_queue[ac] = queue;
        }
 
        /* Allocate the CAB queue for softAP and GO interfaces */
        if (vif->type == NL80211_IFTYPE_AP) {
-               u8 queue = find_first_zero_bit(data.used_hw_queues,
+               u8 queue = find_first_zero_bit(&used_hw_queues,
                                               mvm->first_agg_queue);
 
                if (queue >= mvm->first_agg_queue) {
@@ -452,14 +452,16 @@ void iwl_mvm_mac_ctxt_release(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 
        switch (vif->type) {
        case NL80211_IFTYPE_P2P_DEVICE:
-               iwl_trans_txq_disable(mvm->trans, IWL_MVM_OFFCHANNEL_QUEUE);
+               iwl_trans_txq_disable(mvm->trans, IWL_MVM_OFFCHANNEL_QUEUE,
+                                     true);
                break;
        case NL80211_IFTYPE_AP:
-               iwl_trans_txq_disable(mvm->trans, vif->cab_queue);
+               iwl_trans_txq_disable(mvm->trans, vif->cab_queue, true);
                /* fall through */
        default:
                for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
-                       iwl_trans_txq_disable(mvm->trans, vif->hw_queue[ac]);
+                       iwl_trans_txq_disable(mvm->trans, vif->hw_queue[ac],
+                                             true);
        }
 }
 
@@ -586,6 +588,7 @@ static void iwl_mvm_mac_ctxt_set_ht_flags(struct iwl_mvm *mvm,
 static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
                                        struct ieee80211_vif *vif,
                                        struct iwl_mac_ctx_cmd *cmd,
+                                       const u8 *bssid_override,
                                        u32 action)
 {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
@@ -593,6 +596,7 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
        bool ht_enabled = !!(vif->bss_conf.ht_operation_mode &
                             IEEE80211_HT_OP_MODE_PROTECTION);
        u8 cck_ack_rates, ofdm_ack_rates;
+       const u8 *bssid = bssid_override ?: vif->bss_conf.bssid;
        int i;
 
        cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
@@ -625,8 +629,9 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
        cmd->tsf_id = cpu_to_le32(mvmvif->tsf_id);
 
        memcpy(cmd->node_addr, vif->addr, ETH_ALEN);
-       if (vif->bss_conf.bssid)
-               memcpy(cmd->bssid_addr, vif->bss_conf.bssid, ETH_ALEN);
+
+       if (bssid)
+               memcpy(cmd->bssid_addr, bssid, ETH_ALEN);
        else
                eth_broadcast_addr(cmd->bssid_addr);
 
@@ -695,7 +700,8 @@ static int iwl_mvm_mac_ctxt_send_cmd(struct iwl_mvm *mvm,
 
 static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm,
                                    struct ieee80211_vif *vif,
-                                   u32 action, bool force_assoc_off)
+                                   u32 action, bool force_assoc_off,
+                                   const u8 *bssid_override)
 {
        struct iwl_mac_ctx_cmd cmd = {};
        struct iwl_mac_data_sta *ctxt_sta;
@@ -703,7 +709,7 @@ static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm,
        WARN_ON(vif->type != NL80211_IFTYPE_STATION);
 
        /* Fill the common data for all mac context types */
-       iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
+       iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, bssid_override, action);
 
        if (vif->p2p) {
                struct ieee80211_p2p_noa_attr *noa =
@@ -784,7 +790,7 @@ static int iwl_mvm_mac_ctxt_cmd_listener(struct iwl_mvm *mvm,
 
        WARN_ON(vif->type != NL80211_IFTYPE_MONITOR);
 
-       iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
+       iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action);
 
        cmd.filter_flags = cpu_to_le32(MAC_FILTER_IN_PROMISC |
                                       MAC_FILTER_IN_CONTROL_AND_MGMT |
@@ -805,7 +811,7 @@ static int iwl_mvm_mac_ctxt_cmd_ibss(struct iwl_mvm *mvm,
 
        WARN_ON(vif->type != NL80211_IFTYPE_ADHOC);
 
-       iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
+       iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action);
 
        cmd.filter_flags = cpu_to_le32(MAC_FILTER_IN_BEACON |
                                       MAC_FILTER_IN_PROBE_REQUEST);
@@ -844,7 +850,7 @@ static int iwl_mvm_mac_ctxt_cmd_p2p_device(struct iwl_mvm *mvm,
 
        WARN_ON(vif->type != NL80211_IFTYPE_P2P_DEVICE);
 
-       iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
+       iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action);
 
        cmd.protection_flags |= cpu_to_le32(MAC_PROT_FLG_TGG_PROTECT);
 
@@ -1072,7 +1078,7 @@ static int iwl_mvm_mac_ctxt_cmd_ap(struct iwl_mvm *mvm,
        WARN_ON(vif->type != NL80211_IFTYPE_AP || vif->p2p);
 
        /* Fill the common data for all mac context types */
-       iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
+       iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action);
 
        /*
         * pass probe requests and beacons from other APs (needed
@@ -1098,7 +1104,7 @@ static int iwl_mvm_mac_ctxt_cmd_go(struct iwl_mvm *mvm,
        WARN_ON(vif->type != NL80211_IFTYPE_AP || !vif->p2p);
 
        /* Fill the common data for all mac context types */
-       iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
+       iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action);
 
        /*
         * pass probe requests and beacons from other APs (needed
@@ -1121,12 +1127,14 @@ static int iwl_mvm_mac_ctxt_cmd_go(struct iwl_mvm *mvm,
 }
 
 static int iwl_mvm_mac_ctx_send(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
-                               u32 action, bool force_assoc_off)
+                               u32 action, bool force_assoc_off,
+                               const u8 *bssid_override)
 {
        switch (vif->type) {
        case NL80211_IFTYPE_STATION:
                return iwl_mvm_mac_ctxt_cmd_sta(mvm, vif, action,
-                                               force_assoc_off);
+                                               force_assoc_off,
+                                               bssid_override);
                break;
        case NL80211_IFTYPE_AP:
                if (!vif->p2p)
@@ -1157,7 +1165,7 @@ int iwl_mvm_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
                return -EIO;
 
        ret = iwl_mvm_mac_ctx_send(mvm, vif, FW_CTXT_ACTION_ADD,
-                                  true);
+                                  true, NULL);
        if (ret)
                return ret;
 
@@ -1169,7 +1177,7 @@ int iwl_mvm_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 }
 
 int iwl_mvm_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
-                            bool force_assoc_off)
+                            bool force_assoc_off, const u8 *bssid_override)
 {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 
@@ -1178,7 +1186,7 @@ int iwl_mvm_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
                return -EIO;
 
        return iwl_mvm_mac_ctx_send(mvm, vif, FW_CTXT_ACTION_MODIFY,
-                                   force_assoc_off);
+                                   force_assoc_off, bssid_override);
 }
 
 int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
index 7c8796584c253d322291ec02cd177539a3869a14..8d1d4b40b0a33cec85b92df7881f81375329f931 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -776,6 +778,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
        iwl_trans_stop_device(mvm->trans);
 
        mvm->scan_status = IWL_MVM_SCAN_NONE;
+       mvm->ps_disabled = false;
 
        /* just in case one was running */
        ieee80211_remain_on_channel_expired(mvm->hw);
@@ -803,6 +806,9 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
         * ucode_down ref until reconfig is complete */
        iwl_mvm_unref_all_except(mvm, IWL_MVM_REF_UCODE_DOWN);
 
+       /* clear any stale d0i3 state */
+       clear_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status);
+
        mvm->vif_count = 0;
        mvm->rx_ba_sessions = 0;
 }
@@ -880,7 +886,7 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)
        /* async_handlers_list is empty and will stay empty: HW is stopped */
 
        /* the fw is stopped, the aux sta is dead: clean up driver state */
-       iwl_mvm_dealloc_int_sta(mvm, &mvm->aux_sta);
+       iwl_mvm_del_aux_sta(mvm);
 
        mutex_unlock(&mvm->mutex);
 
@@ -965,10 +971,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
         */
        if (vif->type == NL80211_IFTYPE_AP ||
            vif->type == NL80211_IFTYPE_ADHOC) {
-               u32 qmask = iwl_mvm_mac_get_queues_mask(mvm, vif);
-               ret = iwl_mvm_allocate_int_sta(mvm, &mvmvif->bcast_sta,
-                                              qmask,
-                                              ieee80211_vif_type_p2p(vif));
+               ret = iwl_mvm_alloc_bcast_sta(mvm, vif);
                if (ret) {
                        IWL_ERR(mvm, "Failed to allocate bcast sta\n");
                        goto out_release;
@@ -1016,7 +1019,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
                if (ret)
                        goto out_unref_phy;
 
-               ret = iwl_mvm_add_bcast_sta(mvm, vif, &mvmvif->bcast_sta);
+               ret = iwl_mvm_add_bcast_sta(mvm, vif);
                if (ret)
                        goto out_unbind;
 
@@ -1057,14 +1060,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
 static void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm,
                                        struct ieee80211_vif *vif)
 {
-       u32 tfd_msk = 0, ac;
-
-       for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
-               if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE)
-                       tfd_msk |= BIT(vif->hw_queue[ac]);
-
-       if (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE)
-               tfd_msk |= BIT(vif->cab_queue);
+       u32 tfd_msk = iwl_mvm_mac_get_queues_mask(mvm, vif);
 
        if (tfd_msk) {
                mutex_lock(&mvm->mutex);
@@ -1120,13 +1116,13 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
                        mvm->noa_duration = 0;
                }
 #endif
-               iwl_mvm_dealloc_int_sta(mvm, &mvmvif->bcast_sta);
+               iwl_mvm_dealloc_bcast_sta(mvm, vif);
                goto out_release;
        }
 
        if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
                mvm->p2p_device_vif = NULL;
-               iwl_mvm_rm_bcast_sta(mvm, &mvmvif->bcast_sta);
+               iwl_mvm_rm_bcast_sta(mvm, vif);
                iwl_mvm_binding_remove_vif(mvm, vif);
                iwl_mvm_phy_ctxt_unref(mvm, mvmvif->phy_ctxt);
                mvmvif->phy_ctxt = NULL;
@@ -1445,10 +1441,23 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
        if (changes & BSS_CHANGED_ASSOC && bss_conf->assoc)
                iwl_mvm_mac_ctxt_recalc_tsf_id(mvm, vif);
 
-       ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false);
+       /*
+        * If we're not associated yet, take the (new) BSSID before associating
+        * so the firmware knows. If we're already associated, then use the old
+        * BSSID here, and we'll send a cleared one later in the CHANGED_ASSOC
+        * branch for disassociation below.
+        */
+       if (changes & BSS_CHANGED_BSSID && !mvmvif->associated)
+               memcpy(mvmvif->bssid, bss_conf->bssid, ETH_ALEN);
+
+       ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false, mvmvif->bssid);
        if (ret)
                IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr);
 
+       /* after sending it once, adopt mac80211 data */
+       memcpy(mvmvif->bssid, bss_conf->bssid, ETH_ALEN);
+       mvmvif->associated = bss_conf->assoc;
+
        if (changes & BSS_CHANGED_ASSOC) {
                if (bss_conf->assoc) {
                        /* add quota for this interface */
@@ -1476,13 +1485,17 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
                                 */
                                u32 dur = (11 * vif->bss_conf.beacon_int) / 10;
                                iwl_mvm_protect_session(mvm, vif, dur, dur,
-                                                       5 * dur);
+                                                       5 * dur, false);
                        }
 
                        iwl_mvm_sf_update(mvm, vif, false);
                        iwl_mvm_power_vif_assoc(mvm, vif);
-                       if (vif->p2p)
+                       if (vif->p2p) {
                                iwl_mvm_ref(mvm, IWL_MVM_REF_P2P_CLIENT);
+                               iwl_mvm_update_smps(mvm, vif,
+                                                   IWL_MVM_SMPS_REQ_PROT,
+                                                   IEEE80211_SMPS_DYNAMIC);
+                       }
                } else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) {
                        /*
                         * If update fails - SF might be running in associated
@@ -1506,6 +1519,13 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
 
                        if (vif->p2p)
                                iwl_mvm_unref(mvm, IWL_MVM_REF_P2P_CLIENT);
+
+                       /* this will take the cleared BSSID from bss_conf */
+                       ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
+                       if (ret)
+                               IWL_ERR(mvm,
+                                       "failed to update MAC %pM (clear after unassoc)\n",
+                                       vif->addr);
                }
 
                iwl_mvm_recalc_multicast(mvm);
@@ -1601,7 +1621,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
 
        /* Send the bcast station. At this stage the TBTT and DTIM time events
         * are added and applied to the scheduler */
-       ret = iwl_mvm_send_bcast_sta(mvm, vif, &mvmvif->bcast_sta);
+       ret = iwl_mvm_send_add_bcast_sta(mvm, vif);
        if (ret)
                goto out_unbind;
 
@@ -1617,7 +1637,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
 
        /* Need to update the P2P Device MAC (only GO, IBSS is single vif) */
        if (vif->p2p && mvm->p2p_device_vif)
-               iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false);
+               iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false, NULL);
 
        iwl_mvm_ref(mvm, IWL_MVM_REF_AP_IBSS);
 
@@ -1633,7 +1653,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
 out_quota_failed:
        iwl_mvm_power_update_mac(mvm);
        mvmvif->ap_ibss_active = false;
-       iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta);
+       iwl_mvm_send_rm_bcast_sta(mvm, vif);
 out_unbind:
        iwl_mvm_binding_remove_vif(mvm, vif);
 out_remove:
@@ -1675,10 +1695,10 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw,
 
        /* Need to update the P2P Device MAC (only GO, IBSS is single vif) */
        if (vif->p2p && mvm->p2p_device_vif)
-               iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false);
+               iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false, NULL);
 
        iwl_mvm_update_quotas(mvm, NULL);
-       iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta);
+       iwl_mvm_send_rm_bcast_sta(mvm, vif);
        iwl_mvm_binding_remove_vif(mvm, vif);
 
        iwl_mvm_power_update_mac(mvm);
@@ -1702,7 +1722,7 @@ iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm,
 
        if (changes & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_HT |
                       BSS_CHANGED_BANDWIDTH) &&
-           iwl_mvm_mac_ctxt_changed(mvm, vif, false))
+           iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL))
                IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr);
 
        /* Need to send a new beacon template to the FW */
@@ -2113,7 +2133,7 @@ static int iwl_mvm_mac_conf_tx(struct ieee80211_hw *hw,
                int ret;
 
                mutex_lock(&mvm->mutex);
-               ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false);
+               ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
                mutex_unlock(&mvm->mutex);
                return ret;
        }
@@ -2141,7 +2161,7 @@ static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw,
 
        mutex_lock(&mvm->mutex);
        /* Try really hard to protect the session and hear a beacon */
-       iwl_mvm_protect_session(mvm, vif, duration, min_duration, 500);
+       iwl_mvm_protect_session(mvm, vif, duration, min_duration, 500, false);
        mutex_unlock(&mvm->mutex);
 
        iwl_mvm_unref(mvm, IWL_MVM_REF_PREPARE_TX);
@@ -2162,7 +2182,7 @@ static void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw,
 
        mutex_lock(&mvm->mutex);
        /* Protect the session to hear the TDLS setup response on the channel */
-       iwl_mvm_protect_session(mvm, vif, duration, duration, 100);
+       iwl_mvm_protect_session(mvm, vif, duration, duration, 100, true);
        mutex_unlock(&mvm->mutex);
 
        iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_TDLS);
@@ -2700,7 +2720,10 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm,
                ret = 0;
                goto out;
        case NL80211_IFTYPE_STATION:
+               break;
        case NL80211_IFTYPE_MONITOR:
+               /* always disable PS when a monitor interface is active */
+               mvmvif->ps_disabled = true;
                break;
        default:
                ret = -EINVAL;
@@ -2732,7 +2755,20 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm,
        if ((vif->type == NL80211_IFTYPE_AP) ||
            (switching_chanctx && (vif->type == NL80211_IFTYPE_STATION))) {
                iwl_mvm_update_quotas(mvm, NULL);
-               iwl_mvm_mac_ctxt_changed(mvm, vif, false);
+               iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
+       }
+
+       if (vif->csa_active && vif->type == NL80211_IFTYPE_STATION) {
+               struct iwl_mvm_sta *mvmsta;
+
+               mvmsta = iwl_mvm_sta_from_staid_protected(mvm,
+                                                         mvmvif->ap_sta_id);
+
+               if (WARN_ON(!mvmsta))
+                       goto out;
+
+               /* TODO: only re-enable after the first beacon */
+               iwl_mvm_sta_modify_disable_tx(mvm, mvmsta, false);
        }
 
        goto out;
@@ -2766,6 +2802,7 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm,
 {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        struct ieee80211_vif *disabled_vif = NULL;
+       struct iwl_mvm_sta *mvmsta;
 
        lockdep_assert_held(&mvm->mutex);
 
@@ -2776,6 +2813,7 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm,
                goto out;
        case NL80211_IFTYPE_MONITOR:
                mvmvif->monitor_active = false;
+               mvmvif->ps_disabled = false;
                break;
        case NL80211_IFTYPE_AP:
                /* This part is triggered only during CSA */
@@ -2796,7 +2834,13 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm,
 
                disabled_vif = vif;
 
-               iwl_mvm_mac_ctxt_changed(mvm, vif, true);
+               mvmsta = iwl_mvm_sta_from_staid_protected(mvm,
+                                                         mvmvif->ap_sta_id);
+
+               if (!WARN_ON(!mvmsta))
+                       iwl_mvm_sta_modify_disable_tx(mvm, mvmsta, true);
+
+               iwl_mvm_mac_ctxt_changed(mvm, vif, true, NULL);
                break;
        default:
                break;
index 2e73d3bd7757605e2483fa00f147086abe32b09c..e292de96e09a00119b6155fa6fa8068e66d13098 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  */
 #define IWL_MVM_CS_UNBLOCK_TX_TIMEOUT 3
 
-enum iwl_mvm_tx_fifo {
-       IWL_MVM_TX_FIFO_BK = 0,
-       IWL_MVM_TX_FIFO_BE,
-       IWL_MVM_TX_FIFO_VI,
-       IWL_MVM_TX_FIFO_VO,
-       IWL_MVM_TX_FIFO_MCAST = 5,
-};
-
 extern const struct ieee80211_ops iwl_mvm_hw_ops;
 
 /**
@@ -203,6 +197,7 @@ enum iwl_dbgfs_pm_mask {
        MVM_DEBUGFS_PM_LPRX_RSSI_THRESHOLD = BIT(7),
        MVM_DEBUGFS_PM_SNOOZE_ENABLE = BIT(8),
        MVM_DEBUGFS_PM_UAPSD_MISBEHAVING = BIT(9),
+       MVM_DEBUGFS_PM_USE_PS_POLL = BIT(10),
 };
 
 struct iwl_dbgfs_pm {
@@ -215,6 +210,7 @@ struct iwl_dbgfs_pm {
        u32 lprx_rssi_threshold;
        bool snooze_ena;
        bool uapsd_misbehaving;
+       bool use_ps_poll;
        int mask;
 };
 
@@ -253,6 +249,7 @@ struct iwl_dbgfs_bf {
 enum iwl_mvm_smps_type_request {
        IWL_MVM_SMPS_REQ_BT_COEX,
        IWL_MVM_SMPS_REQ_TT,
+       IWL_MVM_SMPS_REQ_PROT,
        NUM_IWL_MVM_SMPS_REQ,
 };
 
@@ -315,6 +312,9 @@ struct iwl_mvm_vif_bf_data {
  * @id: between 0 and 3
  * @color: to solve races upon MAC addition and removal
  * @ap_sta_id: the sta_id of the AP - valid only if VIF type is STA
+ * @bssid: BSSID for this (client) interface
+ * @associated: indicates that we're currently associated, used only for
+ *     managing the firmware state in iwl_mvm_bss_info_changed_station()
  * @uploaded: indicates the MAC context has been added to the device
  * @ap_ibss_active: indicates that AP/IBSS is configured and that the interface
  *     should get quota etc.
@@ -323,6 +323,7 @@ struct iwl_mvm_vif_bf_data {
  *     interface should get quota etc.
  * @low_latency: indicates that this interface is in low-latency mode
  *     (VMACLowLatencyMode)
+ * @ps_disabled: indicates that this interface requires PS to be disabled
  * @queue_params: QoS params for this MAC
  * @bcast_sta: station used for broadcast packets. Used by the following
  *  vifs: P2P_DEVICE, GO and AP.
@@ -335,11 +336,15 @@ struct iwl_mvm_vif {
        u16 color;
        u8 ap_sta_id;
 
+       u8 bssid[ETH_ALEN];
+       bool associated;
+
        bool uploaded;
        bool ap_ibss_active;
        bool pm_enabled;
        bool monitor_active;
        bool low_latency;
+       bool ps_disabled;
        struct iwl_mvm_vif_bf_data bf_data;
 
        u32 ap_beacon_time;
@@ -512,6 +517,10 @@ enum {
        D0I3_PENDING_WAKEUP,
 };
 
+#define IWL_MVM_DEBUG_SET_TEMPERATURE_DISABLE 0xff
+#define IWL_MVM_DEBUG_SET_TEMPERATURE_MIN -100
+#define IWL_MVM_DEBUG_SET_TEMPERATURE_MAX 200
+
 struct iwl_mvm {
        /* for logger access */
        struct device *dev;
@@ -553,9 +562,8 @@ struct iwl_mvm {
 
        struct mvm_statistics_rx rx_stats;
 
-       unsigned long transport_queue_stop;
        u8 queue_to_mac80211[IWL_MAX_HW_QUEUES];
-       atomic_t queue_stop_count[IWL_MAX_HW_QUEUES];
+       atomic_t mac80211_queue_stop_count[IEEE80211_MAX_QUEUES];
 
        const char *nvm_file_name;
        struct iwl_nvm_data *nvm_data;
@@ -694,6 +702,12 @@ struct iwl_mvm {
        /* Thermal Throttling and CTkill */
        struct iwl_mvm_tt_mgmt thermal_throttle;
        s32 temperature;        /* Celsius */
+       /*
+        * Debug option to set the NIC temperature. This option makes the
+        * driver think this is the actual NIC temperature, and ignore the
+        * real temperature that is received from the fw
+        */
+       bool temperature_test;  /* Debug test temperature is enabled */
 
 #ifdef CONFIG_NL80211_TESTMODE
        u32 noa_duration;
@@ -706,7 +720,7 @@ struct iwl_mvm {
        u8 last_agg_queue;
 
        /* Indicate if device power save is allowed */
-       bool ps_disabled;
+       u8 ps_disabled; /* u8 instead of bool to ease debugfs_create_* usage */
 
        struct ieee80211_vif __rcu *csa_vif;
        struct ieee80211_vif __rcu *csa_tx_blocked_vif;
@@ -714,6 +728,8 @@ struct iwl_mvm {
 
        /* system time of last beacon (for AP/GO interface) */
        u32 ap_last_beacon_gp2;
+
+       u8 low_latency_agg_frame_limit;
 };
 
 /* Extract MVM priv from op_mode and _hw */
@@ -878,7 +894,7 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
 void iwl_mvm_mac_ctxt_release(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
 int iwl_mvm_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
 int iwl_mvm_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
-                            bool force_assoc_off);
+                            bool force_assoc_off, const u8 *bssid_override);
 int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
 u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm,
                                struct ieee80211_vif *vif);
@@ -968,6 +984,7 @@ int rs_pretty_print_rate(char *buf, const u32 rate);
 /* power management */
 int iwl_mvm_power_update_device(struct iwl_mvm *mvm);
 int iwl_mvm_power_update_mac(struct iwl_mvm *mvm);
+int iwl_mvm_power_update_ps(struct iwl_mvm *mvm);
 int iwl_mvm_power_mac_dbgfs_read(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
                                 char *buf, int bufsz);
 
index cfdd314fdd5decd15b57bf02b3ad63eb1ab16cd0..4fafd4bd89f41d32e375030e2da55a62d05bf148 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 9bfb95e89cfbbdab1b446c55d5423a795eb87e03..adcbf4c8edd86c37400029db065dd1720b8cdfed 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 610dbcb0dc279d97dda32ded4df2b387a4577333..87f278cc9b2c74655ba9d71c14dc9894f9396662 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -415,6 +417,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
                mvm->first_agg_queue = 12;
        }
        mvm->sf_state = SF_UNINIT;
+       mvm->low_latency_agg_frame_limit = 1;
 
        mutex_init(&mvm->mutex);
        mutex_init(&mvm->d0i3_suspend_mutex);
@@ -456,7 +459,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
        trans_cfg.command_names = iwl_mvm_cmd_strings;
 
        trans_cfg.cmd_queue = IWL_MVM_CMD_QUEUE;
-       trans_cfg.cmd_fifo = IWL_MVM_CMD_FIFO;
+       trans_cfg.cmd_fifo = IWL_MVM_TX_FIFO_CMD;
 
        snprintf(mvm->hw->wiphy->fw_version,
                 sizeof(mvm->hw->wiphy->fw_version),
@@ -494,7 +497,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
                goto out_free;
 
        /*
-        * Even if nvm exists in the nvm_file driver should read agin the nvm
+        * Even if nvm exists in the nvm_file driver should read again the nvm
         * from the nic because there might be entries that exist in the OTP
         * and not in the file.
         * for nics with no_power_up_nic_in_init: rely completley on nvm_file
@@ -700,14 +703,13 @@ static void iwl_mvm_stop_sw_queue(struct iwl_op_mode *op_mode, int queue)
        if (WARN_ON_ONCE(mq == IWL_INVALID_MAC80211_QUEUE))
                return;
 
-       if (atomic_inc_return(&mvm->queue_stop_count[mq]) > 1) {
+       if (atomic_inc_return(&mvm->mac80211_queue_stop_count[mq]) > 1) {
                IWL_DEBUG_TX_QUEUES(mvm,
                                    "queue %d (mac80211 %d) already stopped\n",
                                    queue, mq);
                return;
        }
 
-       set_bit(mq, &mvm->transport_queue_stop);
        ieee80211_stop_queue(mvm->hw, mq);
 }
 
@@ -719,15 +721,13 @@ static void iwl_mvm_wake_sw_queue(struct iwl_op_mode *op_mode, int queue)
        if (WARN_ON_ONCE(mq == IWL_INVALID_MAC80211_QUEUE))
                return;
 
-       if (atomic_dec_return(&mvm->queue_stop_count[mq]) > 0) {
+       if (atomic_dec_return(&mvm->mac80211_queue_stop_count[mq]) > 0) {
                IWL_DEBUG_TX_QUEUES(mvm,
-                                   "queue %d (mac80211 %d) already awake\n",
+                                   "queue %d (mac80211 %d) still stopped\n",
                                    queue, mq);
                return;
        }
 
-       clear_bit(mq, &mvm->transport_queue_stop);
-
        ieee80211_wake_queue(mvm->hw, mq);
 }
 
index 6cc243f7cf602b8f926baa11d4a59c30db965e0c..12283b55ee84ff5aa49b629d3bd4b702b9826720 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 2b2d10800a55e1b90f3f4da4c91bd6cfe09629a8..e7a6626fe8397691904f6ef1321541f002837ac9 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -198,8 +200,15 @@ static void iwl_mvm_power_configure_uapsd(struct iwl_mvm *mvm,
                }
        }
 
-       if (!(cmd->flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK)))
+       if (!(cmd->flags & cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK))) {
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+               /* set advanced pm flag with no uapsd ACs to enable ps-poll */
+               if (mvmvif->dbgfs_pm.use_ps_poll)
+                       cmd->flags |=
+                               cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK);
+#endif
                return;
+       }
 
        cmd->flags |= cpu_to_le16(POWER_FLAGS_UAPSD_MISBEHAVING_ENA_MSK);
 
@@ -497,13 +506,31 @@ struct iwl_power_vifs {
        bool p2p_tdls;
 };
 
-static void iwl_mvm_power_iterator(void *_data, u8 *mac,
-                                  struct ieee80211_vif *vif)
+static void iwl_mvm_power_disable_pm_iterator(void *_data, u8* mac,
+                                             struct ieee80211_vif *vif)
 {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
-       struct iwl_power_vifs *power_iterator = _data;
 
        mvmvif->pm_enabled = false;
+}
+
+static void iwl_mvm_power_ps_disabled_iterator(void *_data, u8* mac,
+                                              struct ieee80211_vif *vif)
+{
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+       bool *disable_ps = _data;
+
+       if (mvmvif->phy_ctxt)
+               if (mvmvif->phy_ctxt->id < MAX_PHYS)
+                       *disable_ps |= mvmvif->ps_disabled;
+}
+
+static void iwl_mvm_power_get_vifs_iterator(void *_data, u8 *mac,
+                                           struct ieee80211_vif *vif)
+{
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+       struct iwl_power_vifs *power_iterator = _data;
+
        switch (ieee80211_vif_type_p2p(vif)) {
        case NL80211_IFTYPE_P2P_DEVICE:
                break;
@@ -559,9 +586,8 @@ static void iwl_mvm_power_iterator(void *_data, u8 *mac,
        }
 }
 
-static void
-iwl_mvm_power_set_pm(struct iwl_mvm *mvm,
-                                   struct iwl_power_vifs *vifs)
+static void iwl_mvm_power_set_pm(struct iwl_mvm *mvm,
+                                struct iwl_power_vifs *vifs)
 {
        struct iwl_mvm_vif *bss_mvmvif = NULL;
        struct iwl_mvm_vif *p2p_mvmvif = NULL;
@@ -571,10 +597,11 @@ iwl_mvm_power_set_pm(struct iwl_mvm *mvm,
 
        lockdep_assert_held(&mvm->mutex);
 
-       /* get vifs info + set pm_enable to false */
+       /* set pm_enable to false */
        ieee80211_iterate_active_interfaces_atomic(mvm->hw,
-                                           IEEE80211_IFACE_ITER_NORMAL,
-                                           iwl_mvm_power_iterator, vifs);
+                                       IEEE80211_IFACE_ITER_NORMAL,
+                                       iwl_mvm_power_disable_pm_iterator,
+                                       NULL);
 
        if (vifs->bss_vif)
                bss_mvmvif = iwl_mvm_vif_from_mac80211(vifs->bss_vif);
@@ -817,32 +844,92 @@ int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm,
        return ret;
 }
 
-int iwl_mvm_power_update_mac(struct iwl_mvm *mvm)
+static int iwl_mvm_power_set_ps(struct iwl_mvm *mvm)
+{
+       bool disable_ps;
+       int ret;
+
+       /* disable PS if CAM */
+       disable_ps = (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM);
+       /* ...or if any of the vifs require PS to be off */
+       ieee80211_iterate_active_interfaces_atomic(mvm->hw,
+                                       IEEE80211_IFACE_ITER_NORMAL,
+                                       iwl_mvm_power_ps_disabled_iterator,
+                                       &disable_ps);
+
+       /* update device power state if it has changed */
+       if (mvm->ps_disabled != disable_ps) {
+               bool old_ps_disabled = mvm->ps_disabled;
+
+               mvm->ps_disabled = disable_ps;
+               ret = iwl_mvm_power_update_device(mvm);
+               if (ret) {
+                       mvm->ps_disabled = old_ps_disabled;
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int iwl_mvm_power_set_ba(struct iwl_mvm *mvm,
+                               struct iwl_power_vifs *vifs)
 {
        struct iwl_mvm_vif *mvmvif;
+       bool ba_enable;
+
+       if (!vifs->bf_vif)
+               return 0;
+
+       mvmvif = iwl_mvm_vif_from_mac80211(vifs->bf_vif);
+
+       ba_enable = !(!mvmvif->pm_enabled || mvm->ps_disabled ||
+                     !vifs->bf_vif->bss_conf.ps ||
+                     iwl_mvm_vif_low_latency(mvmvif));
+
+       return iwl_mvm_update_beacon_abort(mvm, vifs->bf_vif, ba_enable);
+}
+
+int iwl_mvm_power_update_ps(struct iwl_mvm *mvm)
+{
+       struct iwl_power_vifs vifs = {
+               .mvm = mvm,
+       };
+       int ret;
+
+       lockdep_assert_held(&mvm->mutex);
+
+       /* get vifs info */
+       ieee80211_iterate_active_interfaces_atomic(mvm->hw,
+                                       IEEE80211_IFACE_ITER_NORMAL,
+                                       iwl_mvm_power_get_vifs_iterator, &vifs);
+
+       ret = iwl_mvm_power_set_ps(mvm);
+       if (ret)
+               return ret;
+
+       return iwl_mvm_power_set_ba(mvm, &vifs);
+}
+
+int iwl_mvm_power_update_mac(struct iwl_mvm *mvm)
+{
        struct iwl_power_vifs vifs = {
                .mvm = mvm,
        };
-       bool ba_enable;
        int ret;
 
        lockdep_assert_held(&mvm->mutex);
 
+       /* get vifs info */
+       ieee80211_iterate_active_interfaces_atomic(mvm->hw,
+                                       IEEE80211_IFACE_ITER_NORMAL,
+                                       iwl_mvm_power_get_vifs_iterator, &vifs);
+
        iwl_mvm_power_set_pm(mvm, &vifs);
 
-       /* disable PS if CAM */
-       if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM) {
-               mvm->ps_disabled = true;
-       } else {
-       /* don't update device power state unless we add / remove monitor */
-               if (vifs.monitor_vif) {
-                       if (vifs.monitor_active)
-                               mvm->ps_disabled = true;
-                       ret = iwl_mvm_power_update_device(mvm);
-                       if (ret)
-                               return ret;
-               }
-       }
+       ret = iwl_mvm_power_set_ps(mvm);
+       if (ret)
+               return ret;
 
        if (vifs.bss_vif) {
                ret = iwl_mvm_power_send_cmd(mvm, vifs.bss_vif);
@@ -856,16 +943,7 @@ int iwl_mvm_power_update_mac(struct iwl_mvm *mvm)
                        return ret;
        }
 
-       if (!vifs.bf_vif)
-               return 0;
-
-       mvmvif = iwl_mvm_vif_from_mac80211(vifs.bf_vif);
-
-       ba_enable = !(!mvmvif->pm_enabled || mvm->ps_disabled ||
-                     !vifs.bf_vif->bss_conf.ps ||
-                     iwl_mvm_vif_low_latency(mvmvif));
-
-       return iwl_mvm_update_beacon_abort(mvm, vifs.bf_vif, ba_enable);
+       return iwl_mvm_power_set_ba(mvm, &vifs);
 }
 
 int iwl_mvm_update_d0i3_power_mode(struct iwl_mvm *mvm,
index 4e20b3ce2b6a320e7fd163fe34a02674788645fc..5fd502db03d17e38036842f8104cad09580287eb 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -161,6 +163,9 @@ static void iwl_mvm_adjust_quota_for_noa(struct iwl_mvm *mvm,
                quota *= (beacon_int - mvm->noa_duration);
                quota /= beacon_int;
 
+               IWL_DEBUG_QUOTA(mvm, "quota: adjust for NoA from %d to %d\n",
+                               le32_to_cpu(cmd->quotas[i].quota), quota);
+
                cmd->quotas[i].quota = cpu_to_le32(quota);
        }
 #endif
@@ -222,6 +227,9 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm,
                quota = (QUOTA_100 - QUOTA_LOWLAT_MIN) / n_non_lowlat;
                quota_rem = QUOTA_100 - n_non_lowlat * quota -
                            QUOTA_LOWLAT_MIN;
+               IWL_DEBUG_QUOTA(mvm,
+                               "quota: low-latency binding active, remaining quota per other binding: %d\n",
+                               quota);
        } else if (num_active_macs) {
                /*
                 * There are 0 or more than 1 low latency bindings, or all the
@@ -230,6 +238,9 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm,
                 */
                quota = QUOTA_100 / num_active_macs;
                quota_rem = QUOTA_100 % num_active_macs;
+               IWL_DEBUG_QUOTA(mvm,
+                               "quota: splitting evenly per binding: %d\n",
+                               quota);
        } else {
                /* values don't really matter - won't be used */
                quota = 0;
@@ -271,6 +282,9 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm,
        for (i = 0; i < MAX_BINDINGS; i++) {
                if (le32_to_cpu(cmd.quotas[i].quota) != 0) {
                        le32_add_cpu(&cmd.quotas[i].quota, quota_rem);
+                       IWL_DEBUG_QUOTA(mvm,
+                                       "quota: giving remainder of %d to binding %d\n",
+                                       quota_rem, i);
                        break;
                }
        }
index c70e959bf0e3d443b17ca8e055ee3dd57fda30a2..17002cf437dbc6040bda94c469ae6365eaf99f91 100644 (file)
@@ -1,6 +1,7 @@
 /******************************************************************************
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -2678,6 +2679,7 @@ static void rs_build_rates_table_from_fixed(struct iwl_mvm *mvm,
        int i;
        int num_rates = ARRAY_SIZE(lq_cmd->rs_table);
        __le32 ucode_rate_le32 = cpu_to_le32(ucode_rate);
+       u8 ant = (ucode_rate & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS;
 
        for (i = 0; i < num_rates; i++)
                lq_cmd->rs_table[i] = ucode_rate_le32;
@@ -2688,6 +2690,13 @@ static void rs_build_rates_table_from_fixed(struct iwl_mvm *mvm,
                lq_cmd->mimo_delim = num_rates - 1;
        else
                lq_cmd->mimo_delim = 0;
+
+       lq_cmd->reduced_tpc = 0;
+
+       if (num_of_ant(ant) == 1)
+               lq_cmd->single_stream_ant_msk = ant;
+
+       lq_cmd->agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
 }
 #endif /* CONFIG_MAC80211_DEBUGFS */
 
@@ -2811,31 +2820,55 @@ static void rs_fill_lq_cmd(struct iwl_mvm *mvm,
                           const struct rs_rate *initial_rate)
 {
        struct iwl_lq_cmd *lq_cmd = &lq_sta->lq;
-       u8 ant = initial_rate->ant;
+       struct iwl_mvm_sta *mvmsta;
+       struct iwl_mvm_vif *mvmvif;
+
+       lq_cmd->agg_disable_start_th = LINK_QUAL_AGG_DISABLE_START_DEF;
+       lq_cmd->agg_time_limit =
+               cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF);
 
 #ifdef CONFIG_MAC80211_DEBUGFS
        if (lq_sta->pers.dbg_fixed_rate) {
                rs_build_rates_table_from_fixed(mvm, lq_cmd,
                                                lq_sta->band,
                                                lq_sta->pers.dbg_fixed_rate);
-               lq_cmd->reduced_tpc = 0;
-               ant = (lq_sta->pers.dbg_fixed_rate & RATE_MCS_ANT_ABC_MSK) >>
-                       RATE_MCS_ANT_POS;
-       } else
+               return;
+       }
 #endif
-               rs_build_rates_table(mvm, lq_sta, initial_rate);
+       if (WARN_ON_ONCE(!sta || !initial_rate))
+               return;
 
-       if (num_of_ant(ant) == 1)
-               lq_cmd->single_stream_ant_msk = ant;
+       rs_build_rates_table(mvm, lq_sta, initial_rate);
 
-       lq_cmd->agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
-       lq_cmd->agg_disable_start_th = LINK_QUAL_AGG_DISABLE_START_DEF;
+       if (num_of_ant(initial_rate->ant) == 1)
+               lq_cmd->single_stream_ant_msk = initial_rate->ant;
 
-       lq_cmd->agg_time_limit =
-               cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF);
+       mvmsta = iwl_mvm_sta_from_mac80211(sta);
+       mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif);
+
+       if (num_of_ant(initial_rate->ant) == 1)
+               lq_cmd->single_stream_ant_msk = initial_rate->ant;
+
+       lq_cmd->agg_frame_cnt_limit = mvmsta->max_agg_bufsize;
 
-       if (sta)
-               lq_cmd->agg_time_limit =
+       /*
+        * In case of low latency, tell the firwmare to leave a frame in the
+        * Tx Fifo so that it can start a transaction in the same TxOP. This
+        * basically allows the firmware to send bursts.
+        */
+       if (iwl_mvm_vif_low_latency(mvmvif)) {
+               lq_cmd->agg_frame_cnt_limit--;
+
+               if (mvm->low_latency_agg_frame_limit)
+                       lq_cmd->agg_frame_cnt_limit =
+                               min(lq_cmd->agg_frame_cnt_limit,
+                                   mvm->low_latency_agg_frame_limit);
+       }
+
+       if (mvmsta->vif->p2p)
+               lq_cmd->flags |= LQ_FLAG_USE_RTS_MSK;
+
+       lq_cmd->agg_time_limit =
                        cpu_to_le16(iwl_mvm_coex_agg_time_limit(mvm, sta));
 }
 
@@ -2932,10 +2965,7 @@ static void rs_program_fix_rate(struct iwl_mvm *mvm,
                       lq_sta->lq.sta_id, lq_sta->pers.dbg_fixed_rate);
 
        if (lq_sta->pers.dbg_fixed_rate) {
-               struct rs_rate rate;
-               rs_rate_from_ucode_rate(lq_sta->pers.dbg_fixed_rate,
-                                       lq_sta->band, &rate);
-               rs_fill_lq_cmd(mvm, NULL, lq_sta, &rate);
+               rs_fill_lq_cmd(mvm, NULL, lq_sta, NULL);
                iwl_mvm_send_lq_cmd(lq_sta->pers.drv, &lq_sta->lq, false);
        }
 }
index 4b98987fc4133f6b7d7c0a21a1d11e57658a35f7..48144e3ad52792db3cf0038c1574b21a1f9a474f 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -491,10 +493,29 @@ int iwl_mvm_rx_statistics(struct iwl_mvm *mvm,
                .mvm = mvm,
        };
 
+       /*
+        * set temperature debug enabled - ignore FW temperature updates
+        * and use the user set temperature.
+        */
+       if (mvm->temperature_test) {
+               if (mvm->temperature < le32_to_cpu(common->temperature))
+                       IWL_DEBUG_TEMP(mvm,
+                                      "Ignoring FW temperature update that is greater than the debug set temperature (debug temp = %d, fw temp = %d)\n",
+                                      mvm->temperature,
+                                      le32_to_cpu(common->temperature));
+               /*
+                * skip iwl_mvm_tt_handler since we are in
+                * temperature debug mode and we are ignoring
+                * the new temperature value
+                */
+               goto update;
+       }
+
        if (mvm->temperature != le32_to_cpu(common->temperature)) {
                mvm->temperature = le32_to_cpu(common->temperature);
                iwl_mvm_tt_handler(mvm);
        }
+update:
        iwl_mvm_update_rx_statistics(mvm, stats);
 
        ieee80211_iterate_active_interfaces(mvm->hw,
index 004b1f5d031429a2798cc1d35464daa6ae59db00..bf9c63dc4a7dcfbf52fec8e7d2889c83dbe06b9d 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -279,6 +281,7 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm,
 {
        bool global_bound = false;
        enum ieee80211_band band;
+       u8 frag_passive_dwell = 0;
 
        ieee80211_iterate_active_interfaces_atomic(mvm->hw,
                                            IEEE80211_IFACE_ITER_NORMAL,
@@ -288,12 +291,36 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm,
        if (!global_bound)
                goto not_bound;
 
-       params->suspend_time = 100;
-       params->max_out_time = 600;
+       params->suspend_time = 30;
+       params->max_out_time = 170;
 
        if (iwl_mvm_low_latency(mvm)) {
-               params->suspend_time = 250;
-               params->max_out_time = 250;
+               if (mvm->fw->ucode_capa.api[0] &
+                   IWL_UCODE_TLV_API_FRAGMENTED_SCAN) {
+                       params->suspend_time = 105;
+                       params->max_out_time = 70;
+                       frag_passive_dwell = 20;
+               } else {
+                       params->suspend_time = 120;
+                       params->max_out_time = 120;
+               }
+       }
+
+       if (frag_passive_dwell && (mvm->fw->ucode_capa.api[0] &
+                                  IWL_UCODE_TLV_API_FRAGMENTED_SCAN)) {
+               /*
+                * P2P device scan should not be fragmented to avoid negative
+                * impact on P2P device discovery. Configure max_out_time to be
+                * equal to dwell time on passive channel. Take a longest
+                * possible value, one that corresponds to 2GHz band
+                */
+               if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
+                       u32 passive_dwell =
+                               iwl_mvm_get_passive_dwell(IEEE80211_BAND_2GHZ);
+                       params->max_out_time = passive_dwell;
+               } else {
+                       params->passive_fragmented = true;
+               }
        }
 
        if (flags & NL80211_SCAN_FLAG_LOW_PRIORITY)
@@ -302,7 +329,11 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm,
 not_bound:
 
        for (band = IEEE80211_BAND_2GHZ; band < IEEE80211_NUM_BANDS; band++) {
-               params->dwell[band].passive = iwl_mvm_get_passive_dwell(band);
+               if (params->passive_fragmented)
+                       params->dwell[band].passive = frag_passive_dwell;
+               else
+                       params->dwell[band].passive =
+                               iwl_mvm_get_passive_dwell(band);
                params->dwell[band].active = iwl_mvm_get_active_dwell(band,
                                                                      n_ssids);
        }
@@ -1100,10 +1131,11 @@ iwl_mvm_build_generic_unified_scan_cmd(struct iwl_mvm *mvm,
                                       struct iwl_mvm_scan_params *params)
 {
        memset(cmd, 0, ksize(cmd));
-       cmd->active_dwell = (u8)params->dwell[IEEE80211_BAND_2GHZ].active;
-       cmd->passive_dwell = (u8)params->dwell[IEEE80211_BAND_2GHZ].passive;
-       /* TODO: Use params; now fragmented isn't used. */
-       cmd->fragmented_dwell = 0;
+       cmd->active_dwell = params->dwell[IEEE80211_BAND_2GHZ].active;
+       cmd->passive_dwell = params->dwell[IEEE80211_BAND_2GHZ].passive;
+       if (params->passive_fragmented)
+               cmd->fragmented_dwell =
+                               params->dwell[IEEE80211_BAND_2GHZ].passive;
        cmd->rx_chain_select = iwl_mvm_scan_rx_chain(mvm);
        cmd->max_out_time = cpu_to_le32(params->max_out_time);
        cmd->suspend_time = cpu_to_le32(params->suspend_time);
index 7edfd15efc9d001f227ea2c35b046c0f47cb55af..d1922afe06f471a501bfd9a5e1ba6da68b763e6e 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 7635488803999cba22a501ef2990f1d96fcc974a..dd9f3a4347f6ad40f1e0992eedbcf0307f976615 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -250,10 +252,14 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
        if (ret)
                return ret;
 
-       /* The first station added is the AP, the others are TDLS STAs */
-       if (vif->type == NL80211_IFTYPE_STATION &&
-           mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT)
-               mvmvif->ap_sta_id = sta_id;
+       if (vif->type == NL80211_IFTYPE_STATION) {
+               if (!sta->tdls) {
+                       WARN_ON(mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT);
+                       mvmvif->ap_sta_id = sta_id;
+               } else {
+                       WARN_ON(mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT);
+               }
+       }
 
        rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], sta);
 
@@ -458,8 +464,9 @@ int iwl_mvm_rm_sta_id(struct iwl_mvm *mvm,
        return ret;
 }
 
-int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta,
-                            u32 qmask, enum nl80211_iftype iftype)
+static int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm,
+                                   struct iwl_mvm_int_sta *sta,
+                                   u32 qmask, enum nl80211_iftype iftype)
 {
        if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
                sta->sta_id = iwl_mvm_find_free_sta_id(mvm, iftype);
@@ -474,7 +481,8 @@ int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta,
        return 0;
 }
 
-void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta)
+static void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm,
+                                   struct iwl_mvm_int_sta *sta)
 {
        RCU_INIT_POINTER(mvm->fw_id_to_mac_id[sta->sta_id], NULL);
        memset(sta, 0, sizeof(struct iwl_mvm_int_sta));
@@ -544,6 +552,13 @@ int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm)
        return ret;
 }
 
+void iwl_mvm_del_aux_sta(struct iwl_mvm *mvm)
+{
+       lockdep_assert_held(&mvm->mutex);
+
+       iwl_mvm_dealloc_int_sta(mvm, &mvm->aux_sta);
+}
+
 /*
  * Send the add station command for the vif's broadcast station.
  * Assumes that the station was already allocated.
@@ -552,10 +567,10 @@ int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm)
  * @vif: the interface to which the broadcast station is added
  * @bsta: the broadcast station to add.
  */
-int iwl_mvm_send_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
-                          struct iwl_mvm_int_sta *bsta)
+int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+       struct iwl_mvm_int_sta *bsta = &mvmvif->bcast_sta;
        static const u8 _baddr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
        const u8 *baddr = _baddr;
 
@@ -573,19 +588,40 @@ int iwl_mvm_send_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
 
 /* Send the FW a request to remove the station from it's internal data
  * structures, but DO NOT remove the entry from the local data structures. */
-int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm,
-                             struct iwl_mvm_int_sta *bsta)
+int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 {
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        int ret;
 
        lockdep_assert_held(&mvm->mutex);
 
-       ret = iwl_mvm_rm_sta_common(mvm, bsta->sta_id);
+       ret = iwl_mvm_rm_sta_common(mvm, mvmvif->bcast_sta.sta_id);
        if (ret)
                IWL_WARN(mvm, "Failed sending remove station\n");
        return ret;
 }
 
+int iwl_mvm_alloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+{
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+       u32 qmask;
+
+       lockdep_assert_held(&mvm->mutex);
+
+       qmask = iwl_mvm_mac_get_queues_mask(mvm, vif);
+
+       /*
+        * The firmware defines the TFD queue mask to only be relevant
+        * for *unicast* queues, so the multicast (CAB) queue shouldn't
+        * be included.
+        */
+       if (vif->type == NL80211_IFTYPE_AP)
+               qmask &= ~BIT(vif->cab_queue);
+
+       return iwl_mvm_allocate_int_sta(mvm, &mvmvif->bcast_sta, qmask,
+                                       ieee80211_vif_type_p2p(vif));
+}
+
 /* Allocate a new station entry for the broadcast station to the given vif,
  * and send it to the FW.
  * Note that each P2P mac should have its own broadcast station.
@@ -593,45 +629,47 @@ int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm,
  * @mvm: the mvm component
  * @vif: the interface to which the broadcast station is added
  * @bsta: the broadcast station to add. */
-int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
-                         struct iwl_mvm_int_sta *bsta)
+int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
-       static const u8 baddr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
-       u32 qmask;
+       struct iwl_mvm_int_sta *bsta = &mvmvif->bcast_sta;
        int ret;
 
        lockdep_assert_held(&mvm->mutex);
 
-       qmask = iwl_mvm_mac_get_queues_mask(mvm, vif);
-       ret = iwl_mvm_allocate_int_sta(mvm, bsta, qmask,
-                                      ieee80211_vif_type_p2p(vif));
+       ret = iwl_mvm_alloc_bcast_sta(mvm, vif);
        if (ret)
                return ret;
 
-       ret = iwl_mvm_add_int_sta_common(mvm, bsta, baddr,
-                                        mvmvif->id, mvmvif->color);
+       ret = iwl_mvm_send_add_bcast_sta(mvm, vif);
 
        if (ret)
                iwl_mvm_dealloc_int_sta(mvm, bsta);
+
        return ret;
 }
 
+void iwl_mvm_dealloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
+{
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+       iwl_mvm_dealloc_int_sta(mvm, &mvmvif->bcast_sta);
+}
+
 /*
  * Send the FW a request to remove the station from it's internal data
  * structures, and in addition remove it from the local data structure.
  */
-int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *bsta)
+int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 {
        int ret;
 
        lockdep_assert_held(&mvm->mutex);
 
-       ret = iwl_mvm_rm_sta_common(mvm, bsta->sta_id);
-       if (ret)
-               return ret;
+       ret = iwl_mvm_send_rm_bcast_sta(mvm, vif);
+
+       iwl_mvm_dealloc_bcast_sta(mvm, vif);
 
-       iwl_mvm_dealloc_int_sta(mvm, bsta);
        return ret;
 }
 
@@ -910,7 +948,7 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
                }
 
                tid_data->ssn = 0xffff;
-               iwl_trans_txq_disable(mvm->trans, txq_id);
+               iwl_trans_txq_disable(mvm->trans, txq_id, true);
                /* fall through */
        case IWL_AGG_STARTING:
        case IWL_EMPTYING_HW_QUEUE_ADDBA:
@@ -965,7 +1003,7 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
                if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), true))
                        IWL_ERR(mvm, "Couldn't flush the AGG queue\n");
 
-               iwl_trans_txq_disable(mvm->trans, tid_data->txq_id);
+               iwl_trans_txq_disable(mvm->trans, tid_data->txq_id, true);
        }
 
        mvm->queue_to_mac80211[tid_data->txq_id] =
index 3b1c8bd6cb54356c41c102402657cf765f617a50..aeb3a7f80cebd90ec8097fa1e415300eca56413f 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -387,17 +389,15 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
                            struct ieee80211_sta *sta, u16 tid);
 
 int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm);
-int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta,
-                            u32 qmask, enum nl80211_iftype iftype);
-void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm,
-                            struct iwl_mvm_int_sta *sta);
-int iwl_mvm_send_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
-                          struct iwl_mvm_int_sta *bsta);
-int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm,
-                             struct iwl_mvm_int_sta *bsta);
-int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
-                         struct iwl_mvm_int_sta *bsta);
-int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *bsta);
+void iwl_mvm_del_aux_sta(struct iwl_mvm *mvm);
+
+int iwl_mvm_alloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+void iwl_mvm_dealloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+
 void iwl_mvm_sta_drained_wk(struct work_struct *wk);
 void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm,
                                struct ieee80211_sta *sta);
index 0241665925f704037faeb73999989a2cadff21b2..79ab6beb6b26c38bce8127ddd3ab2cf9511bc200 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 33e5041f1efc191d69b847ad729c3bb434784dfc..447d3b1003df2a2c890a0307797393d892d3b95e 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -348,6 +350,38 @@ unlock:
        return 0;
 }
 
+static bool iwl_mvm_te_notif(struct iwl_notif_wait_data *notif_wait,
+                            struct iwl_rx_packet *pkt, void *data)
+{
+       struct iwl_mvm *mvm =
+               container_of(notif_wait, struct iwl_mvm, notif_wait);
+       struct iwl_mvm_time_event_data *te_data = data;
+       struct iwl_time_event_notif *resp;
+       int resp_len = iwl_rx_packet_payload_len(pkt);
+
+       if (WARN_ON(pkt->hdr.cmd != TIME_EVENT_NOTIFICATION))
+               return true;
+
+       if (WARN_ON_ONCE(resp_len != sizeof(*resp))) {
+               IWL_ERR(mvm, "Invalid TIME_EVENT_NOTIFICATION response\n");
+               return true;
+       }
+
+       resp = (void *)pkt->data;
+
+       /* te_data->uid is already set in the TIME_EVENT_CMD response */
+       if (le32_to_cpu(resp->unique_id) != te_data->uid)
+               return false;
+
+       IWL_DEBUG_TE(mvm, "TIME_EVENT_NOTIFICATION response - UID = 0x%x\n",
+                    te_data->uid);
+       if (!resp->status)
+               IWL_ERR(mvm,
+                       "TIME_EVENT_NOTIFICATION received but not executed\n");
+
+       return true;
+}
+
 static bool iwl_mvm_time_event_response(struct iwl_notif_wait_data *notif_wait,
                                        struct iwl_rx_packet *pkt, void *data)
 {
@@ -441,10 +475,12 @@ static int iwl_mvm_time_event_send_add(struct iwl_mvm *mvm,
 void iwl_mvm_protect_session(struct iwl_mvm *mvm,
                             struct ieee80211_vif *vif,
                             u32 duration, u32 min_duration,
-                            u32 max_delay)
+                            u32 max_delay, bool wait_for_notif)
 {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data;
+       const u8 te_notif_response[] = { TIME_EVENT_NOTIFICATION };
+       struct iwl_notification_wait wait_te_notif;
        struct iwl_time_event_cmd time_cmd = {};
 
        lockdep_assert_held(&mvm->mutex);
@@ -489,7 +525,28 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm,
                                      TE_V2_NOTIF_HOST_EVENT_END |
                                      T2_V2_START_IMMEDIATELY);
 
-       iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);
+       if (!wait_for_notif) {
+               iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);
+               return;
+       }
+
+       /*
+        * Create notification_wait for the TIME_EVENT_NOTIFICATION to use
+        * right after we send the time event
+        */
+       iwl_init_notification_wait(&mvm->notif_wait, &wait_te_notif,
+                                  te_notif_response,
+                                  ARRAY_SIZE(te_notif_response),
+                                  iwl_mvm_te_notif, te_data);
+
+       /* If TE was sent OK - wait for the notification that started */
+       if (iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd)) {
+               IWL_ERR(mvm, "Failed to add TE to protect session\n");
+               iwl_remove_notification(&mvm->notif_wait, &wait_te_notif);
+       } else if (iwl_wait_notification(&mvm->notif_wait, &wait_te_notif,
+                                        TU_TO_JIFFIES(max_delay))) {
+               IWL_ERR(mvm, "Failed to protect session until TE\n");
+       }
 }
 
 /*
index 2f48a90d4ad3e61b010609e2c1d13357c92b3427..bee3b2446b35dd29b08e7066b08c0a8f08135672 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * @min_duration: will start a new session if the current session will end
  *     in less than min_duration.
  * @max_delay: maximum delay before starting the time event (in TU)
+ * @wait_for_notif: true if it is required that a time event notification be
+ *     waited for (that the time event has been scheduled before returning)
  *
  * This function can be used to start a session protection which means that the
  * fw will stay on the channel for %duration_ms milliseconds. This function
- * will block (sleep) until the session starts. This function can also be used
+ * can block (sleep) until the session starts. This function can also be used
  * to extend a currently running session.
  * This function is meant to be used for BSS association for example, where we
  * want to make sure that the fw stays on the channel during the association.
 void iwl_mvm_protect_session(struct iwl_mvm *mvm,
                             struct ieee80211_vif *vif,
                             u32 duration, u32 min_duration,
-                            u32 max_delay);
+                            u32 max_delay, bool wait_for_notif);
 
 /**
  * iwl_mvm_stop_session_protection - cancel the session protection.
index 0464599c111e07522fa5efb36fa3828639c17b0c..c3e1fe4282f15e03120a2e13666e2c545b87c0d1 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -314,14 +316,26 @@ static void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm)
 {
        u32 duration = mvm->thermal_throttle.params->ct_kill_duration;
 
+       if (test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status))
+               return;
+
        IWL_ERR(mvm, "Enter CT Kill\n");
        iwl_mvm_set_hw_ctkill_state(mvm, true);
-       schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit,
-                             round_jiffies_relative(duration * HZ));
+
+       /* Don't schedule an exit work if we're in test mode, since
+        * the temperature will not change unless we manually set it
+        * again (or disable testing).
+        */
+       if (!mvm->temperature_test)
+               schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit,
+                                     round_jiffies_relative(duration * HZ));
 }
 
 static void iwl_mvm_exit_ctkill(struct iwl_mvm *mvm)
 {
+       if (!test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status))
+               return;
+
        IWL_ERR(mvm, "Exit CT Kill\n");
        iwl_mvm_set_hw_ctkill_state(mvm, false);
 }
@@ -444,6 +458,12 @@ void iwl_mvm_tt_handler(struct iwl_mvm *mvm)
                return;
        }
 
+       if (params->support_ct_kill &&
+           temperature <= tt->params->ct_kill_exit) {
+               iwl_mvm_exit_ctkill(mvm);
+               return;
+       }
+
        if (params->support_dynamic_smps) {
                if (!tt->dynamic_smps &&
                    temperature >= params->dynamic_smps_entry) {
index dbc870713882937c381a90ea2a1c31a2a9f60af8..963edb8656adc12f6412b1583ede3ef78ba0152d 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -482,7 +484,7 @@ static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm,
                IWL_DEBUG_TX_QUEUES(mvm,
                                    "Can continue DELBA flow ssn = next_recl = %d\n",
                                    tid_data->next_reclaimed);
-               iwl_trans_txq_disable(mvm->trans, tid_data->txq_id);
+               iwl_trans_txq_disable(mvm->trans, tid_data->txq_id, true);
                tid_data->state = IWL_AGG_OFF;
                /*
                 * we can't hold the mutex - but since we are after a sequence
index ac249da8a22b0840ce8de74638ba1969a119c67c..1958f298ac8ba5864b020d308e7b9871ce5d9343 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -387,15 +389,19 @@ struct iwl_error_event_table {
 struct iwl_umac_error_event_table {
        u32 valid;              /* (nonzero) valid, (0) log is empty */
        u32 error_id;           /* type of error */
-       u32 pc;                 /* program counter */
        u32 blink1;             /* branch link */
        u32 blink2;             /* branch link */
        u32 ilink1;             /* interrupt link */
        u32 ilink2;             /* interrupt link */
        u32 data1;              /* error-specific data */
        u32 data2;              /* error-specific data */
-       u32 line;               /* source code line of error */
-       u32 umac_ver;           /* umac version */
+       u32 data3;              /* error-specific data */
+       u32 umac_fw_ver;        /* UMAC version */
+       u32 umac_fw_api_ver;    /* UMAC FW API ver */
+       u32 frame_pointer;      /* core register 27*/
+       u32 stack_pointer;      /* core register 28 */
+       u32 cmd_header; /* latest host cmd sent to UMAC */
+       u32 nic_isr_pref;       /* ISR status register */
 } __packed;
 
 #define ERROR_START_OFFSET  (1 * sizeof(u32))
@@ -409,7 +415,7 @@ static void iwl_mvm_dump_umac_error_log(struct iwl_mvm *mvm)
 
        base = mvm->umac_error_event_table;
 
-       if (base < 0x800000 || base >= 0x80C000) {
+       if (base < 0x800000) {
                IWL_ERR(mvm,
                        "Not valid error log pointer 0x%08X for %s uCode\n",
                        base,
@@ -428,14 +434,19 @@ static void iwl_mvm_dump_umac_error_log(struct iwl_mvm *mvm)
 
        IWL_ERR(mvm, "0x%08X | %-28s\n", table.error_id,
                desc_lookup(table.error_id));
-       IWL_ERR(mvm, "0x%08X | umac uPc\n", table.pc);
        IWL_ERR(mvm, "0x%08X | umac branchlink1\n", table.blink1);
        IWL_ERR(mvm, "0x%08X | umac branchlink2\n", table.blink2);
        IWL_ERR(mvm, "0x%08X | umac interruptlink1\n", table.ilink1);
        IWL_ERR(mvm, "0x%08X | umac interruptlink2\n", table.ilink2);
        IWL_ERR(mvm, "0x%08X | umac data1\n", table.data1);
        IWL_ERR(mvm, "0x%08X | umac data2\n", table.data2);
-       IWL_ERR(mvm, "0x%08X | umac version\n", table.umac_ver);
+       IWL_ERR(mvm, "0x%08X | umac data3\n", table.data3);
+       IWL_ERR(mvm, "0x%08X | umac version\n", table.umac_fw_ver);
+       IWL_ERR(mvm, "0x%08X | umac api version\n", table.umac_fw_api_ver);
+       IWL_ERR(mvm, "0x%08X | frame pointer\n", table.frame_pointer);
+       IWL_ERR(mvm, "0x%08X | stack pointer\n", table.stack_pointer);
+       IWL_ERR(mvm, "0x%08X | last host cmd\n", table.cmd_header);
+       IWL_ERR(mvm, "0x%08X | isr status reg\n", table.nic_isr_pref);
 }
 
 void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
index f0e722ced08032511514840bb9d13f5485000b2f..dbbbf23082a2900e1a3b49fb27fe081739e4facd 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 78f72c34438aaabd7be9f94386a4e093689a2906..a4fedc4a74482291664ea1921df891f90ab417bf 100644 (file)
@@ -1,6 +1,7 @@
 /******************************************************************************
  *
  * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
@@ -364,9 +365,10 @@ int iwl_pcie_tx_init(struct iwl_trans *trans);
 void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr);
 int iwl_pcie_tx_stop(struct iwl_trans *trans);
 void iwl_pcie_tx_free(struct iwl_trans *trans);
-void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo,
-                              int sta_id, int tid, int frame_limit, u16 ssn);
-void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int queue);
+void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int queue, u16 ssn,
+                              const struct iwl_trans_txq_scd_cfg *cfg);
+void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int queue,
+                               bool configure_scd);
 int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
                      struct iwl_device_cmd *dev_cmd, int txq_id);
 void iwl_pcie_txq_check_wrptrs(struct iwl_trans *trans);
index a2698e5e062c990524d12e1d112818977aeccc2b..702f47fb16fe6c30a1958fa1f7ae393e2dbec186 100644 (file)
@@ -1,6 +1,7 @@
 /******************************************************************************
  *
  * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
index 06e04aaf61eea9609d619be4e0afdf407dd307d4..3076e0e9a490029296eeeaf34d853017a2915baf 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 6acccb19c4f3030956e0d701a037c1227d7121b1..a6336b4aa3a42f54ecc577b4c140e4adcad9290b 100644 (file)
@@ -1,6 +1,7 @@
 /******************************************************************************
  *
  * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
@@ -34,6 +35,7 @@
 #include "iwl-csr.h"
 #include "iwl-prph.h"
 #include "iwl-io.h"
+#include "iwl-scd.h"
 #include "iwl-op-mode.h"
 #include "internal.h"
 /* FIXME: need to abstract out TX command (once we know what it looks like) */
@@ -644,17 +646,6 @@ static void iwl_pcie_txq_free(struct iwl_trans *trans, int txq_id)
        memset(txq, 0, sizeof(*txq));
 }
 
-/*
- * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask
- */
-static void iwl_pcie_txq_set_sched(struct iwl_trans *trans, u32 mask)
-{
-       struct iwl_trans_pcie __maybe_unused *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       iwl_write_prph(trans, SCD_TXFACT, mask);
-}
-
 void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
@@ -692,7 +683,7 @@ void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr)
                                trans_pcie->cmd_fifo);
 
        /* Activate all Tx DMA/FIFO channels */
-       iwl_pcie_txq_set_sched(trans, IWL_MASK(0, 7));
+       iwl_scd_activate_fifos(trans);
 
        /* Enable DMA channel */
        for (chan = 0; chan < FH_TCSR_CHNL_NUM; chan++)
@@ -745,7 +736,7 @@ int iwl_pcie_tx_stop(struct iwl_trans *trans)
        /* Turn off all Tx DMA fifos */
        spin_lock(&trans_pcie->irq_lock);
 
-       iwl_pcie_txq_set_sched(trans, 0);
+       iwl_scd_deactivate_fifos(trans);
 
        /* Stop each Tx DMA channel, and wait for it to be idle */
        for (ch = 0; ch < FH_TCSR_CHNL_NUM; ch++) {
@@ -886,7 +877,7 @@ int iwl_pcie_tx_init(struct iwl_trans *trans)
        spin_lock(&trans_pcie->irq_lock);
 
        /* Turn off all Tx DMA fifos */
-       iwl_write_prph(trans, SCD_TXFACT, 0);
+       iwl_scd_deactivate_fifos(trans);
 
        /* Tell NIC where to find the "keep warm" buffer */
        iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG,
@@ -1072,55 +1063,52 @@ static int iwl_pcie_txq_set_ratid_map(struct iwl_trans *trans, u16 ra_tid,
        return 0;
 }
 
-static inline void iwl_pcie_txq_set_inactive(struct iwl_trans *trans,
-                                            u16 txq_id)
-{
-       /* Simply stop the queue, but don't change any configuration;
-        * the SCD_ACT_EN bit is the write-enable mask for the ACTIVE bit. */
-       iwl_write_prph(trans,
-               SCD_QUEUE_STATUS_BITS(txq_id),
-               (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)|
-               (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
-}
-
 /* Receiver address (actually, Rx station's index into station table),
  * combined with Traffic ID (QOS priority), in format used by Tx Scheduler */
 #define BUILD_RAxTID(sta_id, tid)      (((sta_id) << 4) + (tid))
 
-void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo,
-                              int sta_id, int tid, int frame_limit, u16 ssn)
+void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn,
+                              const struct iwl_trans_txq_scd_cfg *cfg)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       int fifo = -1;
 
        if (test_and_set_bit(txq_id, trans_pcie->queue_used))
                WARN_ONCE(1, "queue %d already used - expect issues", txq_id);
 
-       /* Stop this Tx queue before configuring it */
-       iwl_pcie_txq_set_inactive(trans, txq_id);
+       if (cfg) {
+               fifo = cfg->fifo;
 
-       /* Set this queue as a chain-building queue unless it is CMD queue */
-       if (txq_id != trans_pcie->cmd_queue)
-               iwl_set_bits_prph(trans, SCD_QUEUECHAIN_SEL, BIT(txq_id));
+               /* Disable the scheduler prior configuring the cmd queue */
+               if (txq_id == trans_pcie->cmd_queue)
+                       iwl_scd_enable_set_active(trans, 0);
 
-       /* If this queue is mapped to a certain station: it is an AGG queue */
-       if (sta_id >= 0) {
-               u16 ra_tid = BUILD_RAxTID(sta_id, tid);
+               /* Stop this Tx queue before configuring it */
+               iwl_scd_txq_set_inactive(trans, txq_id);
 
-               /* Map receiver-address / traffic-ID to this queue */
-               iwl_pcie_txq_set_ratid_map(trans, ra_tid, txq_id);
+               /* Set this queue as a chain-building queue unless it is CMD */
+               if (txq_id != trans_pcie->cmd_queue)
+                       iwl_scd_txq_set_chain(trans, txq_id);
 
-               /* enable aggregations for the queue */
-               iwl_set_bits_prph(trans, SCD_AGGR_SEL, BIT(txq_id));
-               trans_pcie->txq[txq_id].ampdu = true;
-       } else {
-               /*
-                * disable aggregations for the queue, this will also make the
-                * ra_tid mapping configuration irrelevant since it is now a
-                * non-AGG queue.
-                */
-               iwl_clear_bits_prph(trans, SCD_AGGR_SEL, BIT(txq_id));
+               if (cfg->aggregate) {
+                       u16 ra_tid = BUILD_RAxTID(cfg->sta_id, cfg->tid);
+
+                       /* Map receiver-address / traffic-ID to this queue */
+                       iwl_pcie_txq_set_ratid_map(trans, ra_tid, txq_id);
+
+                       /* enable aggregations for the queue */
+                       iwl_scd_txq_enable_agg(trans, txq_id);
+                       trans_pcie->txq[txq_id].ampdu = true;
+               } else {
+                       /*
+                        * disable aggregations for the queue, this will also
+                        * make the ra_tid mapping configuration irrelevant
+                        * since it is now a non-AGG queue.
+                        */
+                       iwl_scd_txq_disable_agg(trans, txq_id);
 
-               ssn = trans_pcie->txq[txq_id].q.read_ptr;
+                       ssn = trans_pcie->txq[txq_id].q.read_ptr;
+               }
        }
 
        /* Place first TFD at index corresponding to start sequence number.
@@ -1128,32 +1116,43 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo,
        trans_pcie->txq[txq_id].q.read_ptr = (ssn & 0xff);
        trans_pcie->txq[txq_id].q.write_ptr = (ssn & 0xff);
 
-       iwl_write_direct32(trans, HBUS_TARG_WRPTR,
-                          (ssn & 0xff) | (txq_id << 8));
-       iwl_write_prph(trans, SCD_QUEUE_RDPTR(txq_id), ssn);
+       if (cfg) {
+               u8 frame_limit = cfg->frame_limit;
+
+               iwl_write_direct32(trans, HBUS_TARG_WRPTR,
+                                  (ssn & 0xff) | (txq_id << 8));
+               iwl_write_prph(trans, SCD_QUEUE_RDPTR(txq_id), ssn);
 
-       /* Set up Tx window size and frame limit for this queue */
-       iwl_trans_write_mem32(trans, trans_pcie->scd_base_addr +
-                       SCD_CONTEXT_QUEUE_OFFSET(txq_id), 0);
-       iwl_trans_write_mem32(trans, trans_pcie->scd_base_addr +
+               /* Set up Tx window size and frame limit for this queue */
+               iwl_trans_write_mem32(trans, trans_pcie->scd_base_addr +
+                               SCD_CONTEXT_QUEUE_OFFSET(txq_id), 0);
+               iwl_trans_write_mem32(trans,
+                       trans_pcie->scd_base_addr +
                        SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32),
                        ((frame_limit << SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
-                               SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
+                                       SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
                        ((frame_limit << SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
-                               SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
-
-       /* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */
-       iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id),
-                      (1 << SCD_QUEUE_STTS_REG_POS_ACTIVE) |
-                      (fifo << SCD_QUEUE_STTS_REG_POS_TXF) |
-                      (1 << SCD_QUEUE_STTS_REG_POS_WSL) |
-                      SCD_QUEUE_STTS_REG_MSK);
+                                       SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
+
+               /* Set up status area in SRAM, map to Tx DMA/FIFO, activate */
+               iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id),
+                              (1 << SCD_QUEUE_STTS_REG_POS_ACTIVE) |
+                              (cfg->fifo << SCD_QUEUE_STTS_REG_POS_TXF) |
+                              (1 << SCD_QUEUE_STTS_REG_POS_WSL) |
+                              SCD_QUEUE_STTS_REG_MSK);
+
+               /* enable the scheduler for this queue (only) */
+               if (txq_id == trans_pcie->cmd_queue)
+                       iwl_scd_enable_set_active(trans, BIT(txq_id));
+       }
+
        trans_pcie->txq[txq_id].active = true;
        IWL_DEBUG_TX_QUEUES(trans, "Activate queue %d on FIFO %d WrPtr: %d\n",
                            txq_id, fifo, ssn & 0xff);
 }
 
-void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id)
+void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id,
+                               bool configure_scd)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        u32 stts_addr = trans_pcie->scd_base_addr +
@@ -1172,10 +1171,12 @@ void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id)
                return;
        }
 
-       iwl_pcie_txq_set_inactive(trans, txq_id);
+       if (configure_scd) {
+               iwl_scd_txq_set_inactive(trans, txq_id);
 
-       iwl_trans_write_mem(trans, stts_addr, (void *)zero_val,
-                           ARRAY_SIZE(zero_val));
+               iwl_trans_write_mem(trans, stts_addr, (void *)zero_val,
+                                   ARRAY_SIZE(zero_val));
+       }
 
        iwl_pcie_txq_unmap(trans, txq_id);
        trans_pcie->txq[txq_id].ampdu = false;
index 47a998d8f99e75bd5f59521a6593ca183cebb77a..22884ba7d6ccdab5c316fd1c4ed895716a628ca2 100644 (file)
@@ -653,6 +653,7 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
                        if (channel &&
                            !(channel->flags & IEEE80211_CHAN_DISABLED)) {
                                bss = cfg80211_inform_bss(wiphy, channel,
+                                       CFG80211_BSS_FTYPE_UNKNOWN,
                                        bssid, get_unaligned_le64(tsfdesc),
                                        capa, intvl, ie, ielen,
                                        LBS_SCAN_RSSI_TO_MBM(rssi),
@@ -1754,6 +1755,7 @@ static void lbs_join_post(struct lbs_private *priv,
 
        bss = cfg80211_inform_bss(priv->wdev->wiphy,
                                  params->chandef.chan,
+                                 CFG80211_BSS_FTYPE_UNKNOWN,
                                  bssid,
                                  0,
                                  capability,
index e2e6bf13c2d8c0858656f494c839da81d0731fa5..c4723b0f5757eba4f1db0b6b3f98bf9f82e38a4a 100644 (file)
@@ -246,7 +246,7 @@ mwifiex_cfg80211_remain_on_channel(struct wiphy *wiphy,
        }
 
        if (priv->roc_cfg.cookie) {
-               wiphy_dbg(wiphy, "info: ongoing ROC, cookie = 0x%llu\n",
+               wiphy_dbg(wiphy, "info: ongoing ROC, cookie = 0x%llx\n",
                          priv->roc_cfg.cookie);
                return -EBUSY;
        }
@@ -1557,6 +1557,7 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv)
                                                       band));
 
        bss = cfg80211_inform_bss(priv->wdev->wiphy, chan,
+                                 CFG80211_BSS_FTYPE_UNKNOWN,
                                  bss_info.bssid, 0, WLAN_CAPABILITY_IBSS,
                                  0, ie_buf, ie_len, 0, GFP_KERNEL);
        cfg80211_put_bss(priv->wdev->wiphy, bss);
index baf0aab63c04d17bb1d01501e0c29f524b4a5f57..985f6c2654fb59ba510c862e1c2615fb278cc1ce 100644 (file)
@@ -1470,7 +1470,7 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
        struct host_cmd_ds_get_hw_spec *hw_spec = &resp->params.hw_spec;
        struct mwifiex_adapter *adapter = priv->adapter;
        struct mwifiex_ie_types_header *tlv;
-       struct hw_spec_fw_api_rev *api_rev;
+       struct hw_spec_api_rev *api_rev;
        u16 resp_size, api_id;
        int i, left_len, parsed_len = 0;
 
@@ -1508,7 +1508,6 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
        }
 
        adapter->fw_release_number = le32_to_cpu(hw_spec->fw_release_number);
-       adapter->fw_api_ver = (adapter->fw_release_number >> 16) & 0xff;
        adapter->number_of_antenna = le16_to_cpu(hw_spec->number_of_antenna);
 
        if (le32_to_cpu(hw_spec->dot_11ac_dev_cap)) {
@@ -1538,23 +1537,30 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
                while (left_len > sizeof(struct mwifiex_ie_types_header)) {
                        tlv = (void *)&hw_spec->tlvs + parsed_len;
                        switch (le16_to_cpu(tlv->type)) {
-                       case TLV_TYPE_FW_API_REV:
-                               api_rev = (struct hw_spec_fw_api_rev *)tlv;
+                       case TLV_TYPE_API_REV:
+                               api_rev = (struct hw_spec_api_rev *)tlv;
                                api_id = le16_to_cpu(api_rev->api_id);
                                switch (api_id) {
                                case KEY_API_VER_ID:
-                                       adapter->fw_key_api_major_ver =
+                                       adapter->key_api_major_ver =
                                                        api_rev->major_ver;
-                                       adapter->fw_key_api_minor_ver =
+                                       adapter->key_api_minor_ver =
                                                        api_rev->minor_ver;
                                        dev_dbg(adapter->dev,
-                                               "fw_key_api v%d.%d\n",
-                                               adapter->fw_key_api_major_ver,
-                                               adapter->fw_key_api_minor_ver);
+                                               "key_api v%d.%d\n",
+                                               adapter->key_api_major_ver,
+                                               adapter->key_api_minor_ver);
+                                       break;
+                               case FW_API_VER_ID:
+                                       adapter->fw_api_ver =
+                                                       api_rev->major_ver;
+                                       dev_dbg(adapter->dev,
+                                               "Firmware api version %d\n",
+                                               adapter->fw_api_ver);
                                        break;
                                default:
                                        dev_warn(adapter->dev,
-                                                "Unknown FW api_id: %d\n",
+                                                "Unknown api_id: %d\n",
                                                 api_id);
                                        break;
                                }
@@ -1567,7 +1573,8 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
                        }
                        parsed_len += le16_to_cpu(tlv->len) +
                                      sizeof(struct mwifiex_ie_types_header);
-                       left_len -= parsed_len;
+                       left_len -= le16_to_cpu(tlv->len) +
+                                     sizeof(struct mwifiex_ie_types_header);
                }
        }
 
index 49da2d53d29455830fb9958bc4ab7dbbcd5d5666..6a703ea18800b417f839ecc284a8d05a74ea6c9f 100644 (file)
@@ -83,7 +83,7 @@ enum KEY_TYPE_ID {
 #define WPA_PN_SIZE            8
 #define KEY_PARAMS_FIXED_LEN   10
 #define KEY_INDEX_MASK         0xf
-#define FW_KEY_API_VER_MAJOR_V2        2
+#define KEY_API_VER_MAJOR_V2   2
 
 #define KEY_MCAST      BIT(0)
 #define KEY_UNICAST    BIT(1)
@@ -170,7 +170,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
 #define TLV_TYPE_COALESCE_RULE      (PROPRIETARY_TLV_BASE_ID + 154)
 #define TLV_TYPE_KEY_PARAM_V2       (PROPRIETARY_TLV_BASE_ID + 156)
 #define TLV_TYPE_TDLS_IDLE_TIMEOUT  (PROPRIETARY_TLV_BASE_ID + 194)
-#define TLV_TYPE_FW_API_REV         (PROPRIETARY_TLV_BASE_ID + 199)
+#define TLV_TYPE_API_REV           (PROPRIETARY_TLV_BASE_ID + 199)
 
 #define MWIFIEX_TX_DATA_BUF_SIZE_2K        2048
 
@@ -844,11 +844,12 @@ struct host_cmd_ds_802_11_ps_mode_enh {
        } params;
 } __packed;
 
-enum FW_API_VER_ID {
+enum API_VER_ID {
        KEY_API_VER_ID = 1,
+       FW_API_VER_ID = 2,
 };
 
-struct hw_spec_fw_api_rev {
+struct hw_spec_api_rev {
        struct mwifiex_ie_types_header header;
        __le16 api_id;
        u8 major_ver;
index 269a277d0a2e6072c092f066c9b23943d8075419..80bda808750851affd881cdae62c93066d11d48a 100644 (file)
@@ -282,8 +282,8 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
        adapter->max_mgmt_ie_index = MAX_MGMT_IE_INDEX;
        adapter->empty_tx_q_cnt = 0;
        adapter->ext_scan = true;
-       adapter->fw_key_api_major_ver = 0;
-       adapter->fw_key_api_minor_ver = 0;
+       adapter->key_api_major_ver = 0;
+       adapter->key_api_minor_ver = 0;
 }
 
 /*
index a2733b1e63f9ec0374f38ba5908b18e52345dfd6..54399631599a7115db2a982aabe98455f8be984c 100644 (file)
@@ -833,7 +833,7 @@ struct mwifiex_adapter {
        struct semaphore *card_sem;
        bool ext_scan;
        u8 fw_api_ver;
-       u8 fw_key_api_major_ver, fw_key_api_minor_ver;
+       u8 key_api_major_ver, key_api_minor_ver;
        struct work_struct iface_work;
        unsigned long iface_work_flags;
        struct memory_type_mapping *mem_type_mapping_tbl;
index dee717a19ddb560956175c43789b2c802f029554..195ef0ca343f1f451f4c039259f64fde5f0f86b1 100644 (file)
@@ -1719,7 +1719,8 @@ mwifiex_parse_single_response_buf(struct mwifiex_private *priv, u8 **bss_info,
 
                if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) {
                        bss = cfg80211_inform_bss(priv->wdev->wiphy,
-                                           chan, bssid, timestamp,
+                                           chan, CFG80211_BSS_FTYPE_UNKNOWN,
+                                           bssid, timestamp,
                                            cap_info_bitmap, beacon_period,
                                            ie_buf, ie_len, rssi, GFP_KERNEL);
                        bss_priv = (struct mwifiex_bss_priv *)bss->priv;
index 733de92a4c611e39da93fb580a272203d269e54f..225f7498048b78315d74a7cfdd6b234350390531 100644 (file)
@@ -965,7 +965,7 @@ mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv,
                                u16 cmd_action, u32 cmd_oid,
                                struct mwifiex_ds_encrypt_key *enc_key)
 {
-       if (priv->adapter->fw_key_api_major_ver == FW_KEY_API_VER_MAJOR_V2)
+       if (priv->adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2)
                return mwifiex_cmd_802_11_key_material_v2(priv, cmd,
                                                          cmd_action, cmd_oid,
                                                          enc_key);
index 08b78baeb846d65ef18680e462991c226c94d5e3..62866b0f083015d66d703feb4bbebd0964f26e66 100644 (file)
@@ -637,7 +637,7 @@ static int mwifiex_ret_802_11_key_material_v2(struct mwifiex_private *priv,
 static int mwifiex_ret_802_11_key_material(struct mwifiex_private *priv,
                                           struct host_cmd_ds_command *resp)
 {
-       if (priv->adapter->fw_key_api_major_ver == FW_KEY_API_VER_MAJOR_V2)
+       if (priv->adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2)
                return mwifiex_ret_802_11_key_material_v2(priv, resp);
        else
                return mwifiex_ret_802_11_key_material_v1(priv, resp);
index caae9738100aa732087e2d03477b063bc1534fe2..b95a29b868d1acef87c912c65c750e70bc3e896f 100644 (file)
@@ -877,7 +877,7 @@ static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv,
                        return -1;
                }
 
-               if (adapter->fw_key_api_major_ver == FW_KEY_API_VER_MAJOR_V2) {
+               if (adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2) {
                        memcpy(encrypt_key->key_material,
                               wep_key->key_material, wep_key->key_length);
                        encrypt_key->key_len = wep_key->key_length;
@@ -903,7 +903,7 @@ static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv,
                        memset(&priv->wep_key[index], 0,
                               sizeof(struct mwifiex_wep_key));
 
-               if (adapter->fw_key_api_major_ver == FW_KEY_API_VER_MAJOR_V2)
+               if (adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2)
                        enc_key = encrypt_key;
                else
                        enc_key = NULL;
index 7118a18b91ba9f2a98a4333a2a5070f00d17a433..4371e12b36f38af6e0946969288ce918dc8487b1 100644 (file)
@@ -357,7 +357,7 @@ static int mwifiex_usb_probe(struct usb_interface *intf,
                card->usb_boot_state = USB8XXX_FW_READY;
                break;
        default:
-               pr_warning("unknown id_product %#x\n", id_product);
+               pr_warn("unknown id_product %#x\n", id_product);
                card->usb_boot_state = USB8XXX_FW_DNLD;
                break;
        }
index cee028321a9ab73eac65ced1048e21fed2ce8e7e..ec79c49de0975651a5e2cdebdd058fc312308537 100644 (file)
@@ -172,7 +172,7 @@ mwifiex_process_mgmt_packet(struct mwifiex_private *priv,
 
        cfg80211_rx_mgmt(priv->wdev, priv->roc_cfg.chan.center_freq,
                         CAL_RSSI(rx_pd->snr, rx_pd->nf), skb->data, pkt_len,
-                        0, GFP_ATOMIC);
+                        0);
 
        return 0;
 }
index d3cf7c3ebfd656d4a592384f41fd348797ed17c8..995846422dc0a9e6176f70ad90927833d1b38614 100644 (file)
@@ -534,7 +534,7 @@ static void ezusb_request_out_callback(struct urb *urb)
 
        if (ctx->killed) {
                spin_unlock_irqrestore(&upriv->req_lock, flags);
-               pr_warning("interrupt called with dead ctx");
+               pr_warn("interrupt called with dead ctx\n");
                goto out;
        }
 
@@ -671,8 +671,8 @@ static void ezusb_request_in_callback(struct ezusb_priv *upriv,
        default:
                spin_unlock_irqrestore(&upriv->req_lock, flags);
 
-               pr_warning("Matched IN URB, unexpected context state(0x%x)",
-                    state);
+               pr_warn("Matched IN URB, unexpected context state(0x%x)\n",
+                       state);
                /* Throw this CTX away and try submitting another */
                del_timer(&ctx->timer);
                ctx->outurb->transfer_flags |= URB_ASYNC_UNLINK;
@@ -1394,12 +1394,12 @@ static void ezusb_bulk_in_callback(struct urb *urb)
                /* When a device gets unplugged we get this every time
                 * we resubmit, flooding the logs.  Since we don't use
                 * USB timeouts, it shouldn't happen any other time*/
-               pr_warning("%s: urb timed out, not resubmiting", __func__);
+               pr_warn("%s: urb timed out, not resubmitting\n", __func__);
                return;
        }
        if (urb->status == -ECONNABORTED) {
-               pr_warning("%s: connection abort, resubmiting urb",
-                    __func__);
+               pr_warn("%s: connection abort, resubmitting urb\n",
+                       __func__);
                goto resubmit;
        }
        if ((urb->status == -EILSEQ)
@@ -1605,13 +1605,10 @@ static int ezusb_probe(struct usb_interface *interface,
        for (i = 0; i < iface_desc->bNumEndpoints; ++i) {
                ep = &interface->altsetting[0].endpoint[i].desc;
 
-               if (((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
-                    == USB_DIR_IN) &&
-                   ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
-                    == USB_ENDPOINT_XFER_BULK)) {
+               if (usb_endpoint_is_bulk_in(ep)) {
                        /* we found a bulk in endpoint */
                        if (upriv->read_urb != NULL) {
-                               pr_warning("Found a second bulk in ep, ignored");
+                               pr_warn("Found a second bulk in ep, ignored\n");
                                continue;
                        }
 
@@ -1621,10 +1618,10 @@ static int ezusb_probe(struct usb_interface *interface,
                                goto error;
                        }
                        if (le16_to_cpu(ep->wMaxPacketSize) != 64)
-                               pr_warning("bulk in: wMaxPacketSize!= 64");
+                               pr_warn("bulk in: wMaxPacketSize!= 64\n");
                        if (ep->bEndpointAddress != (2 | USB_DIR_IN))
-                               pr_warning("bulk in: bEndpointAddress: %d",
-                                    ep->bEndpointAddress);
+                               pr_warn("bulk in: bEndpointAddress: %d\n",
+                                       ep->bEndpointAddress);
                        upriv->read_pipe = usb_rcvbulkpipe(udev,
                                                         ep->
                                                         bEndpointAddress);
@@ -1636,21 +1633,18 @@ static int ezusb_probe(struct usb_interface *interface,
                        }
                }
 
-               if (((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
-                    == USB_DIR_OUT) &&
-                   ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
-                    == USB_ENDPOINT_XFER_BULK)) {
+               if (usb_endpoint_is_bulk_out(ep)) {
                        /* we found a bulk out endpoint */
                        if (upriv->bap_buf != NULL) {
-                               pr_warning("Found a second bulk out ep, ignored");
+                               pr_warn("Found a second bulk out ep, ignored\n");
                                continue;
                        }
 
                        if (le16_to_cpu(ep->wMaxPacketSize) != 64)
-                               pr_warning("bulk out: wMaxPacketSize != 64");
+                               pr_warn("bulk out: wMaxPacketSize != 64\n");
                        if (ep->bEndpointAddress != 2)
-                               pr_warning("bulk out: bEndpointAddress: %d",
-                                    ep->bEndpointAddress);
+                               pr_warn("bulk out: bEndpointAddress: %d\n",
+                                       ep->bEndpointAddress);
                        upriv->write_pipe = usb_sndbulkpipe(udev,
                                                          ep->
                                                          bEndpointAddress);
index e175b9b8561b594299d69d237624e3604932d22f..2c66166add705ca64b0390cfe4602d2d15c70fdd 100644 (file)
@@ -123,9 +123,10 @@ static void orinoco_add_hostscan_result(struct orinoco_private *priv,
        beacon_interval = le16_to_cpu(bss->a.beacon_interv);
        signal = SIGNAL_TO_MBM(le16_to_cpu(bss->a.level));
 
-       cbss = cfg80211_inform_bss(wiphy, channel, bss->a.bssid, timestamp,
-                                  capability, beacon_interval, ie_buf, ie_len,
-                                  signal, GFP_KERNEL);
+       cbss = cfg80211_inform_bss(wiphy, channel, CFG80211_BSS_FTYPE_UNKNOWN,
+                                  bss->a.bssid, timestamp, capability,
+                                  beacon_interval, ie_buf, ie_len, signal,
+                                  GFP_KERNEL);
        cfg80211_put_bss(wiphy, cbss);
 }
 
@@ -156,9 +157,10 @@ void orinoco_add_extscan_result(struct orinoco_private *priv,
        ie = bss->data;
        signal = SIGNAL_TO_MBM(bss->level);
 
-       cbss = cfg80211_inform_bss(wiphy, channel, bss->bssid, timestamp,
-                                  capability, beacon_interval, ie, ie_len,
-                                  signal, GFP_KERNEL);
+       cbss = cfg80211_inform_bss(wiphy, channel, CFG80211_BSS_FTYPE_UNKNOWN,
+                                  bss->bssid, timestamp, capability,
+                                  beacon_interval, ie, ie_len, signal,
+                                  GFP_KERNEL);
        cfg80211_put_bss(wiphy, cbss);
 }
 
index e79848fbcca1e1e5397410745589703e3cad903a..524c2f02dd821196a843c961687e73096ea02d65 100644 (file)
@@ -3,7 +3,8 @@
    Written by Corey Thomas
 */
 
-#ifndef RAYLINK_H
+#ifndef _RAY_CS_H_
+#define _RAY_CS_H_
 
 struct beacon_rx {
     struct mac_header mac;
@@ -69,4 +70,4 @@ typedef struct ray_dev_t {
 } ray_dev_t;
 /*****************************************************************************/
 
-#endif /* RAYLINK_H */
+#endif /* _RAY_CS_H_ */
index 3c3b98b152c30bb7a5b1f2cd3ce20793eb63c212..b21ed64e15df1e3842ae1b48e89fc3ffc918d6c7 100644 (file)
@@ -1,4 +1,5 @@
-#ifndef RAYLINK_H
+#ifndef _RAYCTL_H_
+#define _RAYCTL_H_
 
 typedef unsigned char UCHAR;
 
@@ -729,4 +730,4 @@ typedef struct snaphdr_t
 #define RAY_IPX_TYPE  0x8137
 #define APPLEARP_TYPE 0x80f3
 /*****************************************************************************/
-#endif /* #ifndef RAYLINK_H */
+#endif /* _RAYCTL_H_ */
index d2a9a08210be1379b4e56ad266c1695ca6486d17..1a4facd1fbf335625ff092064b3dfa58f4e869d1 100644 (file)
@@ -2022,9 +2022,10 @@ static bool rndis_bss_info_update(struct usbnet *usbdev,
        capability = le16_to_cpu(fixed->capabilities);
        beacon_interval = le16_to_cpu(fixed->beacon_interval);
 
-       bss = cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid->mac,
-               timestamp, capability, beacon_interval, ie, ie_len, signal,
-               GFP_KERNEL);
+       bss = cfg80211_inform_bss(priv->wdev.wiphy, channel,
+                                 CFG80211_BSS_FTYPE_UNKNOWN, bssid->mac,
+                                 timestamp, capability, beacon_interval,
+                                 ie, ie_len, signal, GFP_KERNEL);
        cfg80211_put_bss(priv->wdev.wiphy, bss);
 
        return (bss != NULL);
@@ -2711,9 +2712,10 @@ static void rndis_wlan_craft_connected_bss(struct usbnet *usbdev, u8 *bssid,
                bssid, (u32)timestamp, capability, beacon_period, ie_len,
                ssid.essid, signal);
 
-       bss = cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid,
-               timestamp, capability, beacon_period, ie_buf, ie_len,
-               signal, GFP_KERNEL);
+       bss = cfg80211_inform_bss(priv->wdev.wiphy, channel,
+                                 CFG80211_BSS_FTYPE_UNKNOWN, bssid,
+                                 timestamp, capability, beacon_period,
+                                 ie_buf, ie_len, signal, GFP_KERNEL);
        cfg80211_put_bss(priv->wdev.wiphy, bss);
 }
 
index a394a9a95919b5dcbaf0f87a19e289e43bafe853..b7434df51e7c27c14347d2f62462c2f988f7aff5 100644 (file)
@@ -52,6 +52,7 @@
  * RF5592 2.4G/5G 2T2R
  * RF3070 2.4G 1T1R
  * RF5360 2.4G 1T1R
+ * RF5362 2.4G 1T1R
  * RF5370 2.4G 1T1R
  * RF5390 2.4G 1T1R
  */
@@ -72,6 +73,7 @@
 #define RF3070                         0x3070
 #define RF3290                         0x3290
 #define RF5360                         0x5360
+#define RF5362                         0x5362
 #define RF5370                         0x5370
 #define RF5372                         0x5372
 #define RF5390                         0x5390
@@ -2145,7 +2147,7 @@ struct mac_iveiv_entry {
 /* Bits [7-4] for RF3320 (RT3370/RT3390), on other chipsets reserved */
 #define RFCSR3_PA1_BIAS_CCK            FIELD8(0x70)
 #define RFCSR3_PA2_CASCODE_BIAS_CCKK   FIELD8(0x80)
-/* Bits for RF3290/RF5360/RF5370/RF5372/RF5390/RF5392 */
+/* Bits for RF3290/RF5360/RF5362/RF5370/RF5372/RF5390/RF5392 */
 #define RFCSR3_VCOCAL_EN               FIELD8(0x80)
 /* Bits for RF3050 */
 #define RFCSR3_BIT1                    FIELD8(0x02)
index 893c9d5f3d6f09c659710a855fd8425a5475d28a..9f57a2db791cf879fd9780b65926df300e461f92 100644 (file)
@@ -3186,6 +3186,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
                break;
        case RF3070:
        case RF5360:
+       case RF5362:
        case RF5370:
        case RF5372:
        case RF5390:
@@ -3203,6 +3204,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
            rt2x00_rf(rt2x00dev, RF3290) ||
            rt2x00_rf(rt2x00dev, RF3322) ||
            rt2x00_rf(rt2x00dev, RF5360) ||
+           rt2x00_rf(rt2x00dev, RF5362) ||
            rt2x00_rf(rt2x00dev, RF5370) ||
            rt2x00_rf(rt2x00dev, RF5372) ||
            rt2x00_rf(rt2x00dev, RF5390) ||
@@ -4317,6 +4319,7 @@ void rt2800_vco_calibration(struct rt2x00_dev *rt2x00dev)
        case RF3070:
        case RF3290:
        case RF5360:
+       case RF5362:
        case RF5370:
        case RF5372:
        case RF5390:
@@ -7095,6 +7098,7 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
        case RF3320:
        case RF3322:
        case RF5360:
+       case RF5362:
        case RF5370:
        case RF5372:
        case RF5390:
@@ -7551,6 +7555,7 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
        case RF3320:
        case RF3322:
        case RF5360:
+       case RF5362:
        case RF5370:
        case RF5372:
        case RF5390:
@@ -7680,6 +7685,7 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
        case RF3070:
        case RF3290:
        case RF5360:
+       case RF5362:
        case RF5370:
        case RF5372:
        case RF5390:
index 33da3dfcfa4f05f112e4271487c9f5131bb3f20a..d4bd550f505c7dcfa59bc60f4c852a5cf6aed39e 100644 (file)
@@ -101,7 +101,7 @@ static bool halbtc_legacy(struct rtl_priv *adapter)
 
        bool is_legacy = false;
 
-       if ((mac->mode == WIRELESS_MODE_B) || (mac->mode == WIRELESS_MODE_B))
+       if ((mac->mode == WIRELESS_MODE_B) || (mac->mode == WIRELESS_MODE_G))
                is_legacy = true;
 
        return is_legacy;
index 361435f8608a125ca4cfdfd38b1bfa6212215ec9..1ac6383e79471f5944e4267f3ae8bc28715c53e2 100644 (file)
@@ -317,6 +317,7 @@ static struct usb_device_id rtl8192c_usb_ids[] = {
        {RTL_USB_DEVICE(0x0bda, 0x5088, rtl92cu_hal_cfg)}, /*Thinkware-CC&C*/
        {RTL_USB_DEVICE(0x0df6, 0x0052, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/
        {RTL_USB_DEVICE(0x0df6, 0x005c, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/
+       {RTL_USB_DEVICE(0x0df6, 0x0070, rtl92cu_hal_cfg)}, /*Sitecom - 150N */
        {RTL_USB_DEVICE(0x0df6, 0x0077, rtl92cu_hal_cfg)}, /*Sitecom-WLA2100V2*/
        {RTL_USB_DEVICE(0x0eb0, 0x9071, rtl92cu_hal_cfg)}, /*NO Brand - Etop*/
        {RTL_USB_DEVICE(0x4856, 0x0091, rtl92cu_hal_cfg)}, /*NetweeN - Feixun*/
index a0aa8fa72392830f65f8c8b52303be5ad44019b9..735be5352143e9a1e757d6953f708a3ce5fd9e54 100644 (file)
@@ -345,7 +345,6 @@ static int wl1251_spi_remove(struct spi_device *spi)
 {
        struct wl1251 *wl = spi_get_drvdata(spi);
 
-       free_irq(wl->irq, wl);
        wl1251_free_hw(wl);
        regulator_disable(wl->vio);
 
index 0420bd45e4ee4f9e16c2de51f4240995cbf45254..27bfb7c11e7bf215fd318c7b9fbf457574b79563 100644 (file)
@@ -65,7 +65,7 @@ extern u32 wl12xx_debug_level;
        pr_err(DRIVER_PREFIX "ERROR " fmt "\n", ##arg)
 
 #define wl1271_warning(fmt, arg...) \
-       pr_warning(DRIVER_PREFIX "WARNING " fmt "\n", ##arg)
+       pr_warn(DRIVER_PREFIX "WARNING " fmt "\n", ##arg)
 
 #define wl1271_notice(fmt, arg...) \
        pr_info(DRIVER_PREFIX fmt "\n", ##arg)
index 392c882b28f03d9da2be51c6487db2d423b58976..69601f6741d9dde900df6162fc4c7ee485123c3a 100644 (file)
@@ -327,23 +327,22 @@ static int wl1271_probe(struct spi_device *spi)
        struct wl12xx_spi_glue *glue;
        struct wlcore_platdev_data pdev_data;
        struct resource res[1];
-       int ret = -ENOMEM;
+       int ret;
 
        memset(&pdev_data, 0x00, sizeof(pdev_data));
 
        pdev_data.pdata = dev_get_platdata(&spi->dev);
        if (!pdev_data.pdata) {
                dev_err(&spi->dev, "no platform data\n");
-               ret = -ENODEV;
-               goto out;
+               return -ENODEV;
        }
 
        pdev_data.if_ops = &spi_ops;
 
-       glue = kzalloc(sizeof(*glue), GFP_KERNEL);
+       glue = devm_kzalloc(&spi->dev, sizeof(*glue), GFP_KERNEL);
        if (!glue) {
                dev_err(&spi->dev, "can't allocate glue\n");
-               goto out;
+               return -ENOMEM;
        }
 
        glue->dev = &spi->dev;
@@ -357,14 +356,13 @@ static int wl1271_probe(struct spi_device *spi)
        ret = spi_setup(spi);
        if (ret < 0) {
                dev_err(glue->dev, "spi_setup failed\n");
-               goto out_free_glue;
+               return ret;
        }
 
        glue->core = platform_device_alloc("wl12xx", PLATFORM_DEVID_AUTO);
        if (!glue->core) {
                dev_err(glue->dev, "can't allocate platform_device\n");
-               ret = -ENOMEM;
-               goto out_free_glue;
+               return -ENOMEM;
        }
 
        glue->core->dev.parent = &spi->dev;
@@ -398,11 +396,6 @@ static int wl1271_probe(struct spi_device *spi)
 
 out_dev_put:
        platform_device_put(glue->core);
-
-out_free_glue:
-       kfree(glue);
-
-out:
        return ret;
 }
 
@@ -411,7 +404,6 @@ static int wl1271_remove(struct spi_device *spi)
        struct wl12xx_spi_glue *glue = spi_get_drvdata(spi);
 
        platform_device_unregister(glue->core);
-       kfree(glue);
 
        return 0;
 }
index e29e15dca86ee3b7d1efc6d84a2607bcd173b449..f379689dde309b7bf63eb511ef7f28a827f71fc5 100644 (file)
@@ -576,6 +576,9 @@ int xenvif_connect(struct xenvif_queue *queue, unsigned long tx_ring_ref,
        init_waitqueue_head(&queue->dealloc_wq);
        atomic_set(&queue->inflight_packets, 0);
 
+       netif_napi_add(queue->vif->dev, &queue->napi, xenvif_poll,
+                       XENVIF_NAPI_WEIGHT);
+
        if (tx_evtchn == rx_evtchn) {
                /* feature-split-event-channels == 0 */
                err = bind_interdomain_evtchn_to_irqhandler(
@@ -629,9 +632,6 @@ int xenvif_connect(struct xenvif_queue *queue, unsigned long tx_ring_ref,
        wake_up_process(queue->task);
        wake_up_process(queue->dealloc_task);
 
-       netif_napi_add(queue->vif->dev, &queue->napi, xenvif_poll,
-                       XENVIF_NAPI_WEIGHT);
-
        return 0;
 
 err_rx_unbind:
index f46a24ffa3fe7be040d488bc49bfba912848fde1..79cb8313c7d8b0b86681bc75867e8b6e5ee746ef 100644 (file)
@@ -453,7 +453,7 @@ static int __init __reserved_mem_reserve_reg(unsigned long node,
                base = dt_mem_next_cell(dt_root_addr_cells, &prop);
                size = dt_mem_next_cell(dt_root_size_cells, &prop);
 
-               if (base && size &&
+               if (size &&
                    early_init_dt_reserve_memory_arch(base, size, nomap) == 0)
                        pr_debug("Reserved memory: reserved region for node '%s': base %pa, size %ld MiB\n",
                                uname, &base, (unsigned long)size / SZ_1M);
index 3e06a699352d0c83a8c660b35d64c97babcc7469..1471e0a223a59286497501e84ed72075aff18b01 100644 (file)
@@ -301,16 +301,17 @@ int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_ar
        /* Get the reg property (if any) */
        addr = of_get_property(device, "reg", NULL);
 
+       /* Try the new-style interrupts-extended first */
+       res = of_parse_phandle_with_args(device, "interrupts-extended",
+                                       "#interrupt-cells", index, out_irq);
+       if (!res)
+               return of_irq_parse_raw(addr, out_irq);
+
        /* Get the interrupts property */
        intspec = of_get_property(device, "interrupts", &intlen);
-       if (intspec == NULL) {
-               /* Try the new-style interrupts-extended */
-               res = of_parse_phandle_with_args(device, "interrupts-extended",
-                                               "#interrupt-cells", index, out_irq);
-               if (res)
-                       return -EINVAL;
-               return of_irq_parse_raw(addr, out_irq);
-       }
+       if (intspec == NULL)
+               return -EINVAL;
+
        intlen /= sizeof(*intspec);
 
        pr_debug(" intspec=%d intlen=%d\n", be32_to_cpup(intspec), intlen);
index d410026678334885bae9e51893fde5f9873a7831..a737cb5974deae12aed1987d5250326ffa350445 100644 (file)
@@ -27,6 +27,7 @@ static struct selftest_results {
 #define NO_OF_NODES 2
 static struct device_node *nodes[NO_OF_NODES];
 static int last_node_index;
+static bool selftest_live_tree;
 
 #define selftest(result, fmt, ...) { \
        if (!(result)) { \
@@ -630,13 +631,6 @@ static int attach_node_and_children(struct device_node *np)
 {
        struct device_node *next, *root = np, *dup;
 
-       if (!np) {
-               pr_warn("%s: No tree to attach; not running tests\n",
-                       __func__);
-               return -ENODATA;
-       }
-
-
        /* skip root node */
        np = np->child;
        /* storing a copy in temporary node */
@@ -672,12 +666,12 @@ static int attach_node_and_children(struct device_node *np)
 static int __init selftest_data_add(void)
 {
        void *selftest_data;
-       struct device_node *selftest_data_node;
+       struct device_node *selftest_data_node, *np;
        extern uint8_t __dtb_testcases_begin[];
        extern uint8_t __dtb_testcases_end[];
        const int size = __dtb_testcases_end - __dtb_testcases_begin;
 
-       if (!size || !of_allnodes) {
+       if (!size) {
                pr_warn("%s: No testcase data to attach; not running tests\n",
                        __func__);
                return -ENODATA;
@@ -692,6 +686,22 @@ static int __init selftest_data_add(void)
                return -ENOMEM;
        }
        of_fdt_unflatten_tree(selftest_data, &selftest_data_node);
+       if (!selftest_data_node) {
+               pr_warn("%s: No tree to attach; not running tests\n", __func__);
+               return -ENODATA;
+       }
+
+       if (!of_allnodes) {
+               /* enabling flag for removing nodes */
+               selftest_live_tree = true;
+               of_allnodes = selftest_data_node;
+
+               for_each_of_allnodes(np)
+                       __of_attach_node_sysfs(np);
+               of_aliases = of_find_node_by_path("/aliases");
+               of_chosen = of_find_node_by_path("/chosen");
+               return 0;
+       }
 
        /* attach the sub-tree to live tree */
        return attach_node_and_children(selftest_data_node);
@@ -723,6 +733,18 @@ static void selftest_data_remove(void)
        struct device_node *np;
        struct property *prop;
 
+       if (selftest_live_tree) {
+               of_node_put(of_aliases);
+               of_node_put(of_chosen);
+               of_aliases = NULL;
+               of_chosen = NULL;
+               for_each_child_of_node(of_allnodes, np)
+                       detach_node_and_children(np);
+               __of_detach_node_sysfs(of_allnodes);
+               of_allnodes = NULL;
+               return;
+       }
+
        while (last_node_index >= 0) {
                if (nodes[last_node_index]) {
                        np = of_find_node_by_path(nodes[last_node_index]->full_name);
index 2d8a4d05d78fc02513fe5a2587e545bc36914f08..90f5ccacce4ba819786506054deec71f05473026 100644 (file)
@@ -1,9 +1,18 @@
 menu "PCI host controller drivers"
        depends on PCI
 
+config PCI_DRA7XX
+       bool "TI DRA7xx PCIe controller"
+       select PCIE_DW
+       depends on OF && HAS_IOMEM && TI_PIPE3
+       help
+        Enables support for the PCIe controller in the DRA7xx SoC.  There
+        are two instances of PCIe controller in DRA7xx.  This controller can
+        act both as EP and RC.  This reuses the Designware core.
+
 config PCI_MVEBU
        bool "Marvell EBU PCIe controller"
-       depends on ARCH_MVEBU || ARCH_DOVE || ARCH_KIRKWOOD
+       depends on ARCH_MVEBU || ARCH_DOVE
        depends on OF
 
 config PCIE_DW
@@ -47,7 +56,7 @@ config PCI_HOST_GENERIC
          controller, such as the one emulated by kvmtool.
 
 config PCIE_SPEAR13XX
-       tristate "STMicroelectronics SPEAr PCIe controller"
+       bool "STMicroelectronics SPEAr PCIe controller"
        depends on ARCH_SPEAR13XX
        select PCIEPORTBUS
        select PCIE_DW
index 0daec7941aba44f30fb17e37857872f2e523fce1..d0e88f114ff93b5e016f7993f012b17ce4ff2631 100644 (file)
@@ -1,4 +1,5 @@
 obj-$(CONFIG_PCIE_DW) += pcie-designware.o
+obj-$(CONFIG_PCI_DRA7XX) += pci-dra7xx.o
 obj-$(CONFIG_PCI_EXYNOS) += pci-exynos.o
 obj-$(CONFIG_PCI_IMX6) += pci-imx6.o
 obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
diff --git a/drivers/pci/host/pci-dra7xx.c b/drivers/pci/host/pci-dra7xx.c
new file mode 100644 (file)
index 0000000..52b34fe
--- /dev/null
@@ -0,0 +1,458 @@
+/*
+ * pcie-dra7xx - PCIe controller driver for TI DRA7xx SoCs
+ *
+ * Copyright (C) 2013-2014 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Kishon Vijay Abraham I <kishon@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/resource.h>
+#include <linux/types.h>
+
+#include "pcie-designware.h"
+
+/* PCIe controller wrapper DRA7XX configuration registers */
+
+#define        PCIECTRL_DRA7XX_CONF_IRQSTATUS_MAIN             0x0024
+#define        PCIECTRL_DRA7XX_CONF_IRQENABLE_SET_MAIN         0x0028
+#define        ERR_SYS                                         BIT(0)
+#define        ERR_FATAL                                       BIT(1)
+#define        ERR_NONFATAL                                    BIT(2)
+#define        ERR_COR                                         BIT(3)
+#define        ERR_AXI                                         BIT(4)
+#define        ERR_ECRC                                        BIT(5)
+#define        PME_TURN_OFF                                    BIT(8)
+#define        PME_TO_ACK                                      BIT(9)
+#define        PM_PME                                          BIT(10)
+#define        LINK_REQ_RST                                    BIT(11)
+#define        LINK_UP_EVT                                     BIT(12)
+#define        CFG_BME_EVT                                     BIT(13)
+#define        CFG_MSE_EVT                                     BIT(14)
+#define        INTERRUPTS (ERR_SYS | ERR_FATAL | ERR_NONFATAL | ERR_COR | ERR_AXI | \
+                       ERR_ECRC | PME_TURN_OFF | PME_TO_ACK | PM_PME | \
+                       LINK_REQ_RST | LINK_UP_EVT | CFG_BME_EVT | CFG_MSE_EVT)
+
+#define        PCIECTRL_DRA7XX_CONF_IRQSTATUS_MSI              0x0034
+#define        PCIECTRL_DRA7XX_CONF_IRQENABLE_SET_MSI          0x0038
+#define        INTA                                            BIT(0)
+#define        INTB                                            BIT(1)
+#define        INTC                                            BIT(2)
+#define        INTD                                            BIT(3)
+#define        MSI                                             BIT(4)
+#define        LEG_EP_INTERRUPTS (INTA | INTB | INTC | INTD)
+
+#define        PCIECTRL_DRA7XX_CONF_DEVICE_CMD                 0x0104
+#define        LTSSM_EN                                        0x1
+
+#define        PCIECTRL_DRA7XX_CONF_PHY_CS                     0x010C
+#define        LINK_UP                                         BIT(16)
+
+struct dra7xx_pcie {
+       void __iomem            *base;
+       struct phy              **phy;
+       int                     phy_count;
+       struct device           *dev;
+       struct pcie_port        pp;
+};
+
+#define to_dra7xx_pcie(x)      container_of((x), struct dra7xx_pcie, pp)
+
+static inline u32 dra7xx_pcie_readl(struct dra7xx_pcie *pcie, u32 offset)
+{
+       return readl(pcie->base + offset);
+}
+
+static inline void dra7xx_pcie_writel(struct dra7xx_pcie *pcie, u32 offset,
+                                     u32 value)
+{
+       writel(value, pcie->base + offset);
+}
+
+static int dra7xx_pcie_link_up(struct pcie_port *pp)
+{
+       struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pp);
+       u32 reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_PHY_CS);
+
+       return !!(reg & LINK_UP);
+}
+
+static int dra7xx_pcie_establish_link(struct pcie_port *pp)
+{
+       u32 reg;
+       unsigned int retries = 1000;
+       struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pp);
+
+       if (dw_pcie_link_up(pp)) {
+               dev_err(pp->dev, "link is already up\n");
+               return 0;
+       }
+
+       reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD);
+       reg |= LTSSM_EN;
+       dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD, reg);
+
+       while (retries--) {
+               reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_PHY_CS);
+               if (reg & LINK_UP)
+                       break;
+               usleep_range(10, 20);
+       }
+
+       if (retries == 0) {
+               dev_err(pp->dev, "link is not up\n");
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+static void dra7xx_pcie_enable_interrupts(struct pcie_port *pp)
+{
+       struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pp);
+
+       dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MAIN,
+                          ~INTERRUPTS);
+       dra7xx_pcie_writel(dra7xx,
+                          PCIECTRL_DRA7XX_CONF_IRQENABLE_SET_MAIN, INTERRUPTS);
+       dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MSI,
+                          ~LEG_EP_INTERRUPTS & ~MSI);
+
+       if (IS_ENABLED(CONFIG_PCI_MSI))
+               dra7xx_pcie_writel(dra7xx,
+                                  PCIECTRL_DRA7XX_CONF_IRQENABLE_SET_MSI, MSI);
+       else
+               dra7xx_pcie_writel(dra7xx,
+                                  PCIECTRL_DRA7XX_CONF_IRQENABLE_SET_MSI,
+                                  LEG_EP_INTERRUPTS);
+}
+
+static void dra7xx_pcie_host_init(struct pcie_port *pp)
+{
+       dw_pcie_setup_rc(pp);
+       dra7xx_pcie_establish_link(pp);
+       if (IS_ENABLED(CONFIG_PCI_MSI))
+               dw_pcie_msi_init(pp);
+       dra7xx_pcie_enable_interrupts(pp);
+}
+
+static struct pcie_host_ops dra7xx_pcie_host_ops = {
+       .link_up = dra7xx_pcie_link_up,
+       .host_init = dra7xx_pcie_host_init,
+};
+
+static int dra7xx_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
+                               irq_hw_number_t hwirq)
+{
+       irq_set_chip_and_handler(irq, &dummy_irq_chip, handle_simple_irq);
+       irq_set_chip_data(irq, domain->host_data);
+       set_irq_flags(irq, IRQF_VALID);
+
+       return 0;
+}
+
+static const struct irq_domain_ops intx_domain_ops = {
+       .map = dra7xx_pcie_intx_map,
+};
+
+static int dra7xx_pcie_init_irq_domain(struct pcie_port *pp)
+{
+       struct device *dev = pp->dev;
+       struct device_node *node = dev->of_node;
+       struct device_node *pcie_intc_node =  of_get_next_child(node, NULL);
+
+       if (!pcie_intc_node) {
+               dev_err(dev, "No PCIe Intc node found\n");
+               return PTR_ERR(pcie_intc_node);
+       }
+
+       pp->irq_domain = irq_domain_add_linear(pcie_intc_node, 4,
+                                              &intx_domain_ops, pp);
+       if (!pp->irq_domain) {
+               dev_err(dev, "Failed to get a INTx IRQ domain\n");
+               return PTR_ERR(pp->irq_domain);
+       }
+
+       return 0;
+}
+
+static irqreturn_t dra7xx_pcie_msi_irq_handler(int irq, void *arg)
+{
+       struct pcie_port *pp = arg;
+       struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pp);
+       u32 reg;
+
+       reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MSI);
+
+       switch (reg) {
+       case MSI:
+               dw_handle_msi_irq(pp);
+               break;
+       case INTA:
+       case INTB:
+       case INTC:
+       case INTD:
+               generic_handle_irq(irq_find_mapping(pp->irq_domain, ffs(reg)));
+               break;
+       }
+
+       dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MSI, reg);
+
+       return IRQ_HANDLED;
+}
+
+
+static irqreturn_t dra7xx_pcie_irq_handler(int irq, void *arg)
+{
+       struct dra7xx_pcie *dra7xx = arg;
+       u32 reg;
+
+       reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MAIN);
+
+       if (reg & ERR_SYS)
+               dev_dbg(dra7xx->dev, "System Error\n");
+
+       if (reg & ERR_FATAL)
+               dev_dbg(dra7xx->dev, "Fatal Error\n");
+
+       if (reg & ERR_NONFATAL)
+               dev_dbg(dra7xx->dev, "Non Fatal Error\n");
+
+       if (reg & ERR_COR)
+               dev_dbg(dra7xx->dev, "Correctable Error\n");
+
+       if (reg & ERR_AXI)
+               dev_dbg(dra7xx->dev, "AXI tag lookup fatal Error\n");
+
+       if (reg & ERR_ECRC)
+               dev_dbg(dra7xx->dev, "ECRC Error\n");
+
+       if (reg & PME_TURN_OFF)
+               dev_dbg(dra7xx->dev,
+                       "Power Management Event Turn-Off message received\n");
+
+       if (reg & PME_TO_ACK)
+               dev_dbg(dra7xx->dev,
+                       "Power Management Turn-Off Ack message received\n");
+
+       if (reg & PM_PME)
+               dev_dbg(dra7xx->dev,
+                       "PM Power Management Event message received\n");
+
+       if (reg & LINK_REQ_RST)
+               dev_dbg(dra7xx->dev, "Link Request Reset\n");
+
+       if (reg & LINK_UP_EVT)
+               dev_dbg(dra7xx->dev, "Link-up state change\n");
+
+       if (reg & CFG_BME_EVT)
+               dev_dbg(dra7xx->dev, "CFG 'Bus Master Enable' change\n");
+
+       if (reg & CFG_MSE_EVT)
+               dev_dbg(dra7xx->dev, "CFG 'Memory Space Enable' change\n");
+
+       dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MAIN, reg);
+
+       return IRQ_HANDLED;
+}
+
+static int add_pcie_port(struct dra7xx_pcie *dra7xx,
+                         struct platform_device *pdev)
+{
+       int ret;
+       struct pcie_port *pp;
+       struct resource *res;
+       struct device *dev = &pdev->dev;
+
+       pp = &dra7xx->pp;
+       pp->dev = dev;
+       pp->ops = &dra7xx_pcie_host_ops;
+
+       pp->irq = platform_get_irq(pdev, 1);
+       if (pp->irq < 0) {
+               dev_err(dev, "missing IRQ resource\n");
+               return -EINVAL;
+       }
+
+       ret = devm_request_irq(&pdev->dev, pp->irq,
+                              dra7xx_pcie_msi_irq_handler, IRQF_SHARED,
+                              "dra7-pcie-msi", pp);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to request irq\n");
+               return ret;
+       }
+
+       if (!IS_ENABLED(CONFIG_PCI_MSI)) {
+               ret = dra7xx_pcie_init_irq_domain(pp);
+               if (ret < 0)
+                       return ret;
+       }
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rc_dbics");
+       pp->dbi_base = devm_ioremap(dev, res->start, resource_size(res));
+       if (!pp->dbi_base)
+               return -ENOMEM;
+
+       ret = dw_pcie_host_init(pp);
+       if (ret) {
+               dev_err(dra7xx->dev, "failed to initialize host\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int __init dra7xx_pcie_probe(struct platform_device *pdev)
+{
+       u32 reg;
+       int ret;
+       int irq;
+       int i;
+       int phy_count;
+       struct phy **phy;
+       void __iomem *base;
+       struct resource *res;
+       struct dra7xx_pcie *dra7xx;
+       struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
+       char name[10];
+
+       dra7xx = devm_kzalloc(dev, sizeof(*dra7xx), GFP_KERNEL);
+       if (!dra7xx)
+               return -ENOMEM;
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(dev, "missing IRQ resource\n");
+               return -EINVAL;
+       }
+
+       ret = devm_request_irq(dev, irq, dra7xx_pcie_irq_handler,
+                              IRQF_SHARED, "dra7xx-pcie-main", dra7xx);
+       if (ret) {
+               dev_err(dev, "failed to request irq\n");
+               return ret;
+       }
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ti_conf");
+       base = devm_ioremap_nocache(dev, res->start, resource_size(res));
+       if (!base)
+               return -ENOMEM;
+
+       phy_count = of_property_count_strings(np, "phy-names");
+       if (phy_count < 0) {
+               dev_err(dev, "unable to find the strings\n");
+               return phy_count;
+       }
+
+       phy = devm_kzalloc(dev, sizeof(*phy) * phy_count, GFP_KERNEL);
+       if (!phy)
+               return -ENOMEM;
+
+       for (i = 0; i < phy_count; i++) {
+               snprintf(name, sizeof(name), "pcie-phy%d", i);
+               phy[i] = devm_phy_get(dev, name);
+               if (IS_ERR(phy[i]))
+                       return PTR_ERR(phy[i]);
+
+               ret = phy_init(phy[i]);
+               if (ret < 0)
+                       goto err_phy;
+
+               ret = phy_power_on(phy[i]);
+               if (ret < 0) {
+                       phy_exit(phy[i]);
+                       goto err_phy;
+               }
+       }
+
+       dra7xx->base = base;
+       dra7xx->phy = phy;
+       dra7xx->dev = dev;
+       dra7xx->phy_count = phy_count;
+
+       pm_runtime_enable(dev);
+       ret = pm_runtime_get_sync(dev);
+       if (IS_ERR_VALUE(ret)) {
+               dev_err(dev, "pm_runtime_get_sync failed\n");
+               goto err_phy;
+       }
+
+       reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD);
+       reg &= ~LTSSM_EN;
+       dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD, reg);
+
+       platform_set_drvdata(pdev, dra7xx);
+
+       ret = add_pcie_port(dra7xx, pdev);
+       if (ret < 0)
+               goto err_add_port;
+
+       return 0;
+
+err_add_port:
+       pm_runtime_put(dev);
+       pm_runtime_disable(dev);
+
+err_phy:
+       while (--i >= 0) {
+               phy_power_off(phy[i]);
+               phy_exit(phy[i]);
+       }
+
+       return ret;
+}
+
+static int __exit dra7xx_pcie_remove(struct platform_device *pdev)
+{
+       struct dra7xx_pcie *dra7xx = platform_get_drvdata(pdev);
+       struct pcie_port *pp = &dra7xx->pp;
+       struct device *dev = &pdev->dev;
+       int count = dra7xx->phy_count;
+
+       if (pp->irq_domain)
+               irq_domain_remove(pp->irq_domain);
+       pm_runtime_put(dev);
+       pm_runtime_disable(dev);
+       while (count--) {
+               phy_power_off(dra7xx->phy[count]);
+               phy_exit(dra7xx->phy[count]);
+       }
+
+       return 0;
+}
+
+static const struct of_device_id of_dra7xx_pcie_match[] = {
+       { .compatible = "ti,dra7-pcie", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, of_dra7xx_pcie_match);
+
+static struct platform_driver dra7xx_pcie_driver = {
+       .remove         = __exit_p(dra7xx_pcie_remove),
+       .driver = {
+               .name   = "dra7-pcie",
+               .owner  = THIS_MODULE,
+               .of_match_table = of_dra7xx_pcie_match,
+       },
+};
+
+module_platform_driver_probe(dra7xx_pcie_driver, dra7xx_pcie_probe);
+
+MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");
+MODULE_DESCRIPTION("TI PCIe controller driver");
+MODULE_LICENSE("GPL v2");
index abd65784618dca13f56960acc051b716ec1bbfd7..0fb0fdb223d5174d6a2e10e750a74194d27a4db6 100644 (file)
@@ -25,6 +25,7 @@
  */
 
 #include <linux/clk.h>
+#include <linux/debugfs.h>
 #include <linux/delay.h>
 #include <linux/export.h>
 #include <linux/interrupt.h>
@@ -276,6 +277,7 @@ struct tegra_pcie {
        unsigned int num_supplies;
 
        const struct tegra_pcie_soc_data *soc_data;
+       struct dentry *debugfs;
 };
 
 struct tegra_pcie_port {
@@ -1739,6 +1741,115 @@ static const struct of_device_id tegra_pcie_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, tegra_pcie_of_match);
 
+static void *tegra_pcie_ports_seq_start(struct seq_file *s, loff_t *pos)
+{
+       struct tegra_pcie *pcie = s->private;
+
+       if (list_empty(&pcie->ports))
+               return NULL;
+
+       seq_printf(s, "Index  Status\n");
+
+       return seq_list_start(&pcie->ports, *pos);
+}
+
+static void *tegra_pcie_ports_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+       struct tegra_pcie *pcie = s->private;
+
+       return seq_list_next(v, &pcie->ports, pos);
+}
+
+static void tegra_pcie_ports_seq_stop(struct seq_file *s, void *v)
+{
+}
+
+static int tegra_pcie_ports_seq_show(struct seq_file *s, void *v)
+{
+       bool up = false, active = false;
+       struct tegra_pcie_port *port;
+       unsigned int value;
+
+       port = list_entry(v, struct tegra_pcie_port, list);
+
+       value = readl(port->base + RP_VEND_XP);
+
+       if (value & RP_VEND_XP_DL_UP)
+               up = true;
+
+       value = readl(port->base + RP_LINK_CONTROL_STATUS);
+
+       if (value & RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE)
+               active = true;
+
+       seq_printf(s, "%2u     ", port->index);
+
+       if (up)
+               seq_printf(s, "up");
+
+       if (active) {
+               if (up)
+                       seq_printf(s, ", ");
+
+               seq_printf(s, "active");
+       }
+
+       seq_printf(s, "\n");
+       return 0;
+}
+
+static const struct seq_operations tegra_pcie_ports_seq_ops = {
+       .start = tegra_pcie_ports_seq_start,
+       .next = tegra_pcie_ports_seq_next,
+       .stop = tegra_pcie_ports_seq_stop,
+       .show = tegra_pcie_ports_seq_show,
+};
+
+static int tegra_pcie_ports_open(struct inode *inode, struct file *file)
+{
+       struct tegra_pcie *pcie = inode->i_private;
+       struct seq_file *s;
+       int err;
+
+       err = seq_open(file, &tegra_pcie_ports_seq_ops);
+       if (err)
+               return err;
+
+       s = file->private_data;
+       s->private = pcie;
+
+       return 0;
+}
+
+static const struct file_operations tegra_pcie_ports_ops = {
+       .owner = THIS_MODULE,
+       .open = tegra_pcie_ports_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
+static int tegra_pcie_debugfs_init(struct tegra_pcie *pcie)
+{
+       struct dentry *file;
+
+       pcie->debugfs = debugfs_create_dir("pcie", NULL);
+       if (!pcie->debugfs)
+               return -ENOMEM;
+
+       file = debugfs_create_file("ports", S_IFREG | S_IRUGO, pcie->debugfs,
+                                  pcie, &tegra_pcie_ports_ops);
+       if (!file)
+               goto remove;
+
+       return 0;
+
+remove:
+       debugfs_remove_recursive(pcie->debugfs);
+       pcie->debugfs = NULL;
+       return -ENOMEM;
+}
+
 static int tegra_pcie_probe(struct platform_device *pdev)
 {
        const struct of_device_id *match;
@@ -1793,6 +1904,13 @@ static int tegra_pcie_probe(struct platform_device *pdev)
                goto disable_msi;
        }
 
+       if (IS_ENABLED(CONFIG_DEBUG_FS)) {
+               err = tegra_pcie_debugfs_init(pcie);
+               if (err < 0)
+                       dev_err(&pdev->dev, "failed to setup debugfs: %d\n",
+                               err);
+       }
+
        platform_set_drvdata(pdev, pcie);
        return 0;
 
index 1eaf4df3618a18a57e0eee175272d5a19646f2bf..52bd3a14356310195af1219e74b7e65091da6d88 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/of_pci.h>
 #include <linux/pci.h>
 #include <linux/pci_regs.h>
+#include <linux/platform_device.h>
 #include <linux/types.h>
 
 #include "pcie-designware.h"
@@ -217,27 +218,47 @@ static int find_valid_pos0(struct pcie_port *pp, int msgvec, int pos, int *pos0)
        return 0;
 }
 
+static void dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
+{
+       unsigned int res, bit, val;
+
+       res = (irq / 32) * 12;
+       bit = irq % 32;
+       dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
+       val &= ~(1 << bit);
+       dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+}
+
 static void clear_irq_range(struct pcie_port *pp, unsigned int irq_base,
                            unsigned int nvec, unsigned int pos)
 {
-       unsigned int i, res, bit, val;
+       unsigned int i;
 
        for (i = 0; i < nvec; i++) {
                irq_set_msi_desc_off(irq_base, i, NULL);
                clear_bit(pos + i, pp->msi_irq_in_use);
                /* Disable corresponding interrupt on MSI controller */
-               res = ((pos + i) / 32) * 12;
-               bit = (pos + i) % 32;
-               dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
-               val &= ~(1 << bit);
-               dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+               if (pp->ops->msi_clear_irq)
+                       pp->ops->msi_clear_irq(pp, pos + i);
+               else
+                       dw_pcie_msi_clear_irq(pp, pos + i);
        }
 }
 
+static void dw_pcie_msi_set_irq(struct pcie_port *pp, int irq)
+{
+       unsigned int res, bit, val;
+
+       res = (irq / 32) * 12;
+       bit = irq % 32;
+       dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
+       val |= 1 << bit;
+       dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+}
+
 static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
 {
-       int res, bit, irq, pos0, pos1, i;
-       u32 val;
+       int irq, pos0, pos1, i;
        struct pcie_port *pp = sys_to_pcie(desc->dev->bus->sysdata);
 
        if (!pp) {
@@ -281,11 +302,10 @@ static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
                }
                set_bit(pos0 + i, pp->msi_irq_in_use);
                /*Enable corresponding interrupt in MSI interrupt controller */
-               res = ((pos0 + i) / 32) * 12;
-               bit = (pos0 + i) % 32;
-               dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
-               val |= 1 << bit;
-               dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+               if (pp->ops->msi_set_irq)
+                       pp->ops->msi_set_irq(pp, pos0 + i);
+               else
+                       dw_pcie_msi_set_irq(pp, pos0 + i);
        }
 
        *pos = pos0;
@@ -353,7 +373,10 @@ static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
         */
        desc->msi_attrib.multiple = msgvec;
 
-       msg.address_lo = virt_to_phys((void *)pp->msi_data);
+       if (pp->ops->get_msi_data)
+               msg.address_lo = pp->ops->get_msi_data(pp);
+       else
+               msg.address_lo = virt_to_phys((void *)pp->msi_data);
        msg.address_hi = 0x0;
        msg.data = pos;
        write_msi_msg(irq, &msg);
@@ -396,10 +419,35 @@ static const struct irq_domain_ops msi_domain_ops = {
 int __init dw_pcie_host_init(struct pcie_port *pp)
 {
        struct device_node *np = pp->dev->of_node;
+       struct platform_device *pdev = to_platform_device(pp->dev);
        struct of_pci_range range;
        struct of_pci_range_parser parser;
-       u32 val;
-       int i;
+       struct resource *cfg_res;
+       u32 val, na, ns;
+       const __be32 *addrp;
+       int i, index;
+
+       /* Find the address cell size and the number of cells in order to get
+        * the untranslated address.
+        */
+       of_property_read_u32(np, "#address-cells", &na);
+       ns = of_n_size_cells(np);
+
+       cfg_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config");
+       if (cfg_res) {
+               pp->config.cfg0_size = resource_size(cfg_res)/2;
+               pp->config.cfg1_size = resource_size(cfg_res)/2;
+               pp->cfg0_base = cfg_res->start;
+               pp->cfg1_base = cfg_res->start + pp->config.cfg0_size;
+
+               /* Find the untranslated configuration space address */
+               index = of_property_match_string(np, "reg-names", "config");
+               addrp = of_get_address(np, index, false, false);
+               pp->cfg0_mod_base = of_read_number(addrp, ns);
+               pp->cfg1_mod_base = pp->cfg0_mod_base + pp->config.cfg0_size;
+       } else {
+               dev_err(pp->dev, "missing *config* reg space\n");
+       }
 
        if (of_pci_range_parser_init(&parser, np)) {
                dev_err(pp->dev, "missing ranges property\n");
@@ -422,17 +470,33 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
                        pp->config.io_size = resource_size(&pp->io);
                        pp->config.io_bus_addr = range.pci_addr;
                        pp->io_base = range.cpu_addr;
+
+                       /* Find the untranslated IO space address */
+                       pp->io_mod_base = of_read_number(parser.range -
+                                                        parser.np + na, ns);
                }
                if (restype == IORESOURCE_MEM) {
                        of_pci_range_to_resource(&range, np, &pp->mem);
                        pp->mem.name = "MEM";
                        pp->config.mem_size = resource_size(&pp->mem);
                        pp->config.mem_bus_addr = range.pci_addr;
+
+                       /* Find the untranslated MEM space address */
+                       pp->mem_mod_base = of_read_number(parser.range -
+                                                         parser.np + na, ns);
                }
                if (restype == 0) {
                        of_pci_range_to_resource(&range, np, &pp->cfg);
                        pp->config.cfg0_size = resource_size(&pp->cfg)/2;
                        pp->config.cfg1_size = resource_size(&pp->cfg)/2;
+                       pp->cfg0_base = pp->cfg.start;
+                       pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
+
+                       /* Find the untranslated configuration space address */
+                       pp->cfg0_mod_base = of_read_number(parser.range -
+                                                          parser.np + na, ns);
+                       pp->cfg1_mod_base = pp->cfg0_mod_base +
+                                           pp->config.cfg0_size;
                }
        }
 
@@ -445,8 +509,6 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
                }
        }
 
-       pp->cfg0_base = pp->cfg.start;
-       pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
        pp->mem_base = pp->mem.start;
 
        pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
@@ -509,9 +571,9 @@ static void dw_pcie_prog_viewport_cfg0(struct pcie_port *pp, u32 busdev)
        /* Program viewport 0 : OUTBOUND : CFG0 */
        dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX0,
                          PCIE_ATU_VIEWPORT);
-       dw_pcie_writel_rc(pp, pp->cfg0_base, PCIE_ATU_LOWER_BASE);
-       dw_pcie_writel_rc(pp, (pp->cfg0_base >> 32), PCIE_ATU_UPPER_BASE);
-       dw_pcie_writel_rc(pp, pp->cfg0_base + pp->config.cfg0_size - 1,
+       dw_pcie_writel_rc(pp, pp->cfg0_mod_base, PCIE_ATU_LOWER_BASE);
+       dw_pcie_writel_rc(pp, (pp->cfg0_mod_base >> 32), PCIE_ATU_UPPER_BASE);
+       dw_pcie_writel_rc(pp, pp->cfg0_mod_base + pp->config.cfg0_size - 1,
                          PCIE_ATU_LIMIT);
        dw_pcie_writel_rc(pp, busdev, PCIE_ATU_LOWER_TARGET);
        dw_pcie_writel_rc(pp, 0, PCIE_ATU_UPPER_TARGET);
@@ -525,9 +587,9 @@ static void dw_pcie_prog_viewport_cfg1(struct pcie_port *pp, u32 busdev)
        dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX1,
                          PCIE_ATU_VIEWPORT);
        dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_CFG1, PCIE_ATU_CR1);
-       dw_pcie_writel_rc(pp, pp->cfg1_base, PCIE_ATU_LOWER_BASE);
-       dw_pcie_writel_rc(pp, (pp->cfg1_base >> 32), PCIE_ATU_UPPER_BASE);
-       dw_pcie_writel_rc(pp, pp->cfg1_base + pp->config.cfg1_size - 1,
+       dw_pcie_writel_rc(pp, pp->cfg1_mod_base, PCIE_ATU_LOWER_BASE);
+       dw_pcie_writel_rc(pp, (pp->cfg1_mod_base >> 32), PCIE_ATU_UPPER_BASE);
+       dw_pcie_writel_rc(pp, pp->cfg1_mod_base + pp->config.cfg1_size - 1,
                          PCIE_ATU_LIMIT);
        dw_pcie_writel_rc(pp, busdev, PCIE_ATU_LOWER_TARGET);
        dw_pcie_writel_rc(pp, 0, PCIE_ATU_UPPER_TARGET);
@@ -540,9 +602,9 @@ static void dw_pcie_prog_viewport_mem_outbound(struct pcie_port *pp)
        dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX0,
                          PCIE_ATU_VIEWPORT);
        dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_MEM, PCIE_ATU_CR1);
-       dw_pcie_writel_rc(pp, pp->mem_base, PCIE_ATU_LOWER_BASE);
-       dw_pcie_writel_rc(pp, (pp->mem_base >> 32), PCIE_ATU_UPPER_BASE);
-       dw_pcie_writel_rc(pp, pp->mem_base + pp->config.mem_size - 1,
+       dw_pcie_writel_rc(pp, pp->mem_mod_base, PCIE_ATU_LOWER_BASE);
+       dw_pcie_writel_rc(pp, (pp->mem_mod_base >> 32), PCIE_ATU_UPPER_BASE);
+       dw_pcie_writel_rc(pp, pp->mem_mod_base + pp->config.mem_size - 1,
                          PCIE_ATU_LIMIT);
        dw_pcie_writel_rc(pp, pp->config.mem_bus_addr, PCIE_ATU_LOWER_TARGET);
        dw_pcie_writel_rc(pp, upper_32_bits(pp->config.mem_bus_addr),
@@ -556,9 +618,9 @@ static void dw_pcie_prog_viewport_io_outbound(struct pcie_port *pp)
        dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX1,
                          PCIE_ATU_VIEWPORT);
        dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_IO, PCIE_ATU_CR1);
-       dw_pcie_writel_rc(pp, pp->io_base, PCIE_ATU_LOWER_BASE);
-       dw_pcie_writel_rc(pp, (pp->io_base >> 32), PCIE_ATU_UPPER_BASE);
-       dw_pcie_writel_rc(pp, pp->io_base + pp->config.io_size - 1,
+       dw_pcie_writel_rc(pp, pp->io_mod_base, PCIE_ATU_LOWER_BASE);
+       dw_pcie_writel_rc(pp, (pp->io_mod_base >> 32), PCIE_ATU_UPPER_BASE);
+       dw_pcie_writel_rc(pp, pp->io_mod_base + pp->config.io_size - 1,
                          PCIE_ATU_LIMIT);
        dw_pcie_writel_rc(pp, pp->config.io_bus_addr, PCIE_ATU_LOWER_TARGET);
        dw_pcie_writel_rc(pp, upper_32_bits(pp->config.io_bus_addr),
@@ -656,7 +718,11 @@ static int dw_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
        }
 
        if (bus->number != pp->root_bus_nr)
-               ret = dw_pcie_rd_other_conf(pp, bus, devfn,
+               if (pp->ops->rd_other_conf)
+                       ret = pp->ops->rd_other_conf(pp, bus, devfn,
+                                               where, size, val);
+               else
+                       ret = dw_pcie_rd_other_conf(pp, bus, devfn,
                                                where, size, val);
        else
                ret = dw_pcie_rd_own_conf(pp, where, size, val);
@@ -679,7 +745,11 @@ static int dw_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
                return PCIBIOS_DEVICE_NOT_FOUND;
 
        if (bus->number != pp->root_bus_nr)
-               ret = dw_pcie_wr_other_conf(pp, bus, devfn,
+               if (pp->ops->wr_other_conf)
+                       ret = pp->ops->wr_other_conf(pp, bus, devfn,
+                                               where, size, val);
+               else
+                       ret = dw_pcie_wr_other_conf(pp, bus, devfn,
                                                where, size, val);
        else
                ret = dw_pcie_wr_own_conf(pp, where, size, val);
index 77f592faa7bf28ee6d86f84cad6ee7cdfd345158..daf81f922cda34e472f4be5c16d5a967f70528da 100644 (file)
@@ -36,11 +36,15 @@ struct pcie_port {
        u8                      root_bus_nr;
        void __iomem            *dbi_base;
        u64                     cfg0_base;
+       u64                     cfg0_mod_base;
        void __iomem            *va_cfg0_base;
        u64                     cfg1_base;
+       u64                     cfg1_mod_base;
        void __iomem            *va_cfg1_base;
        u64                     io_base;
+       u64                     io_mod_base;
        u64                     mem_base;
+       u64                     mem_mod_base;
        struct resource         cfg;
        struct resource         io;
        struct resource         mem;
@@ -61,8 +65,15 @@ struct pcie_host_ops {
                        u32 val, void __iomem *dbi_base);
        int (*rd_own_conf)(struct pcie_port *pp, int where, int size, u32 *val);
        int (*wr_own_conf)(struct pcie_port *pp, int where, int size, u32 val);
+       int (*rd_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
+                       unsigned int devfn, int where, int size, u32 *val);
+       int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
+                       unsigned int devfn, int where, int size, u32 val);
        int (*link_up)(struct pcie_port *pp);
        void (*host_init)(struct pcie_port *pp);
+       void (*msi_set_irq)(struct pcie_port *pp, int irq);
+       void (*msi_clear_irq)(struct pcie_port *pp, int irq);
+       u32 (*get_msi_data)(struct pcie_port *pp);
 };
 
 int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val);
index a53a689a2bfaa371024369dfc7a9e8dc72fc2ca3..8c6fd8d4dd3cedc26401492346fd8ab79893dac9 100644 (file)
@@ -620,8 +620,7 @@ static void abx500_gpio_dbg_show_one(struct seq_file *s,
        } else
                seq_printf(s, " %-9s", chip->get(chip, offset) ? "hi" : "lo");
 
-       if (pctldev)
-               mode = abx500_get_mode(pctldev, chip, offset);
+       mode = abx500_get_mode(pctldev, chip, offset);
 
        seq_printf(s, " %s", (mode < 0) ? "unknown" : modes[mode]);
 
index af1ba4fc150dd4e10509b8e53ccab89458d7d09a..60464a2648aa0dfb7c31fe13c75dc419472c3b31 100644 (file)
@@ -497,10 +497,10 @@ static struct at91_pinctrl_mux_ops at91sam9x5_ops = {
 static void at91_pin_dbg(const struct device *dev, const struct at91_pmx_pin *pin)
 {
        if (pin->mux) {
-               dev_dbg(dev, "pio%c%d configured as periph%c with conf = 0x%lu\n",
+               dev_dbg(dev, "pio%c%d configured as periph%c with conf = 0x%lx\n",
                        pin->bank + 'A', pin->pin, pin->mux - 1 + 'A', pin->conf);
        } else {
-               dev_dbg(dev, "pio%c%d configured as gpio with conf = 0x%lu\n",
+               dev_dbg(dev, "pio%c%d configured as gpio with conf = 0x%lx\n",
                        pin->bank + 'A', pin->pin, pin->conf);
        }
 }
index 5e8b2e04cd7a322e6aefa85adbd3996ad04cc19e..0c372a300cb88058e9957e017db99f3d127fb08d 100644 (file)
@@ -438,7 +438,7 @@ static int rockchip_set_mux(struct rockchip_pin_bank *bank, int pin, int mux)
        int reg, ret, mask;
        unsigned long flags;
        u8 bit;
-       u32 data;
+       u32 data, rmask;
 
        if (iomux_num > 3)
                return -EINVAL;
@@ -478,8 +478,9 @@ static int rockchip_set_mux(struct rockchip_pin_bank *bank, int pin, int mux)
        spin_lock_irqsave(&bank->slock, flags);
 
        data = (mask << (bit + 16));
+       rmask = data | (data >> 16);
        data |= (mux & mask) << bit;
-       ret = regmap_write(regmap, reg, data);
+       ret = regmap_update_bits(regmap, reg, rmask, data);
 
        spin_unlock_irqrestore(&bank->slock, flags);
 
@@ -634,7 +635,7 @@ static int rk3288_set_drive(struct rockchip_pin_bank *bank, int pin_num,
        struct regmap *regmap;
        unsigned long flags;
        int reg, ret, i;
-       u32 data;
+       u32 data, rmask;
        u8 bit;
 
        rk3288_calc_drv_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
@@ -657,9 +658,10 @@ static int rk3288_set_drive(struct rockchip_pin_bank *bank, int pin_num,
 
        /* enable the write to the equivalent lower bits */
        data = ((1 << RK3288_DRV_BITS_PER_PIN) - 1) << (bit + 16);
+       rmask = data | (data >> 16);
        data |= (ret << bit);
 
-       ret = regmap_write(regmap, reg, data);
+       ret = regmap_update_bits(regmap, reg, rmask, data);
        spin_unlock_irqrestore(&bank->slock, flags);
 
        return ret;
@@ -722,7 +724,7 @@ static int rockchip_set_pull(struct rockchip_pin_bank *bank,
        int reg, ret;
        unsigned long flags;
        u8 bit;
-       u32 data;
+       u32 data, rmask;
 
        dev_dbg(info->dev, "setting pull of GPIO%d-%d to %d\n",
                 bank->bank_num, pin_num, pull);
@@ -750,6 +752,7 @@ static int rockchip_set_pull(struct rockchip_pin_bank *bank,
 
                /* enable the write to the equivalent lower bits */
                data = ((1 << RK3188_PULL_BITS_PER_PIN) - 1) << (bit + 16);
+               rmask = data | (data >> 16);
 
                switch (pull) {
                case PIN_CONFIG_BIAS_DISABLE:
@@ -770,7 +773,7 @@ static int rockchip_set_pull(struct rockchip_pin_bank *bank,
                        return -EINVAL;
                }
 
-               ret = regmap_write(regmap, reg, data);
+               ret = regmap_update_bits(regmap, reg, rmask, data);
 
                spin_unlock_irqrestore(&bank->slock, flags);
                break;
index a06620474845964667bea51b387395360f206bf0..e641b4226c422fe9afac1d9be8eee73e65509b02 100644 (file)
@@ -680,7 +680,7 @@ static struct phy *tegra_xusb_padctl_xlate(struct device *dev,
        if (args->args_count <= 0)
                return ERR_PTR(-EINVAL);
 
-       if (index > ARRAY_SIZE(padctl->phys))
+       if (index >= ARRAY_SIZE(padctl->phys))
                return ERR_PTR(-EINVAL);
 
        return padctl->phys[index];
@@ -930,7 +930,8 @@ static int tegra_xusb_padctl_probe(struct platform_device *pdev)
 
        padctl->provider = devm_of_phy_provider_register(&pdev->dev,
                                                         tegra_xusb_padctl_xlate);
-       if (err < 0) {
+       if (IS_ERR(padctl->provider)) {
+               err = PTR_ERR(padctl->provider);
                dev_err(&pdev->dev, "failed to register PHYs: %d\n", err);
                goto unregister;
        }
index 003bfd874a6155ca8dc70a50d527c3151ee6a797..d7154ed0b0eb19347fa1bd26ca82dee99a4c9e87 100644 (file)
@@ -127,14 +127,10 @@ static int exynos_irq_set_type(struct irq_data *irqd, unsigned int type)
        struct irq_chip *chip = irq_data_get_irq_chip(irqd);
        struct exynos_irq_chip *our_chip = to_exynos_irq_chip(chip);
        struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
-       struct samsung_pin_bank_type *bank_type = bank->type;
        struct samsung_pinctrl_drv_data *d = bank->drvdata;
-       unsigned int pin = irqd->hwirq;
-       unsigned int shift = EXYNOS_EINT_CON_LEN * pin;
+       unsigned int shift = EXYNOS_EINT_CON_LEN * irqd->hwirq;
        unsigned int con, trig_type;
        unsigned long reg_con = our_chip->eint_con + bank->eint_offset;
-       unsigned long flags;
-       unsigned int mask;
 
        switch (type) {
        case IRQ_TYPE_EDGE_RISING:
@@ -167,8 +163,32 @@ static int exynos_irq_set_type(struct irq_data *irqd, unsigned int type)
        con |= trig_type << shift;
        writel(con, d->virt_base + reg_con);
 
+       return 0;
+}
+
+static int exynos_irq_request_resources(struct irq_data *irqd)
+{
+       struct irq_chip *chip = irq_data_get_irq_chip(irqd);
+       struct exynos_irq_chip *our_chip = to_exynos_irq_chip(chip);
+       struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
+       struct samsung_pin_bank_type *bank_type = bank->type;
+       struct samsung_pinctrl_drv_data *d = bank->drvdata;
+       unsigned int shift = EXYNOS_EINT_CON_LEN * irqd->hwirq;
+       unsigned long reg_con = our_chip->eint_con + bank->eint_offset;
+       unsigned long flags;
+       unsigned int mask;
+       unsigned int con;
+       int ret;
+
+       ret = gpio_lock_as_irq(&bank->gpio_chip, irqd->hwirq);
+       if (ret) {
+               dev_err(bank->gpio_chip.dev, "unable to lock pin %s-%lu IRQ\n",
+                       bank->name, irqd->hwirq);
+               return ret;
+       }
+
        reg_con = bank->pctl_offset + bank_type->reg_offset[PINCFG_TYPE_FUNC];
-       shift = pin * bank_type->fld_width[PINCFG_TYPE_FUNC];
+       shift = irqd->hwirq * bank_type->fld_width[PINCFG_TYPE_FUNC];
        mask = (1 << bank_type->fld_width[PINCFG_TYPE_FUNC]) - 1;
 
        spin_lock_irqsave(&bank->slock, flags);
@@ -180,9 +200,42 @@ static int exynos_irq_set_type(struct irq_data *irqd, unsigned int type)
 
        spin_unlock_irqrestore(&bank->slock, flags);
 
+       exynos_irq_unmask(irqd);
+
        return 0;
 }
 
+static void exynos_irq_release_resources(struct irq_data *irqd)
+{
+       struct irq_chip *chip = irq_data_get_irq_chip(irqd);
+       struct exynos_irq_chip *our_chip = to_exynos_irq_chip(chip);
+       struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
+       struct samsung_pin_bank_type *bank_type = bank->type;
+       struct samsung_pinctrl_drv_data *d = bank->drvdata;
+       unsigned int shift = EXYNOS_EINT_CON_LEN * irqd->hwirq;
+       unsigned long reg_con = our_chip->eint_con + bank->eint_offset;
+       unsigned long flags;
+       unsigned int mask;
+       unsigned int con;
+
+       reg_con = bank->pctl_offset + bank_type->reg_offset[PINCFG_TYPE_FUNC];
+       shift = irqd->hwirq * bank_type->fld_width[PINCFG_TYPE_FUNC];
+       mask = (1 << bank_type->fld_width[PINCFG_TYPE_FUNC]) - 1;
+
+       exynos_irq_mask(irqd);
+
+       spin_lock_irqsave(&bank->slock, flags);
+
+       con = readl(d->virt_base + reg_con);
+       con &= ~(mask << shift);
+       con |= FUNC_INPUT << shift;
+       writel(con, d->virt_base + reg_con);
+
+       spin_unlock_irqrestore(&bank->slock, flags);
+
+       gpio_unlock_as_irq(&bank->gpio_chip, irqd->hwirq);
+}
+
 /*
  * irq_chip for gpio interrupts.
  */
@@ -193,6 +246,8 @@ static struct exynos_irq_chip exynos_gpio_irq_chip = {
                .irq_mask = exynos_irq_mask,
                .irq_ack = exynos_irq_ack,
                .irq_set_type = exynos_irq_set_type,
+               .irq_request_resources = exynos_irq_request_resources,
+               .irq_release_resources = exynos_irq_release_resources,
        },
        .eint_con = EXYNOS_GPIO_ECON_OFFSET,
        .eint_mask = EXYNOS_GPIO_EMASK_OFFSET,
@@ -336,6 +391,8 @@ static struct exynos_irq_chip exynos_wkup_irq_chip = {
                .irq_ack = exynos_irq_ack,
                .irq_set_type = exynos_irq_set_type,
                .irq_set_wake = exynos_wkup_irq_set_wake,
+               .irq_request_resources = exynos_irq_request_resources,
+               .irq_release_resources = exynos_irq_release_resources,
        },
        .eint_con = EXYNOS_WKUP_ECON_OFFSET,
        .eint_mask = EXYNOS_WKUP_EMASK_OFFSET,
index 2b882320e8e97077fca276200a970e10296be939..5cedc9d26390fae0d5aa77c785116eceaac3146b 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/gpio.h>
 
 /* pinmux function number for pin as gpio output line */
+#define FUNC_INPUT     0x0
 #define FUNC_OUTPUT    0x1
 
 /**
index 576d41b459e97fd4f3675e2a8f1cf981a3a2b410..c6e5deba238ec5dc9311ba51e21a52cca70327d2 100644 (file)
@@ -4509,24 +4509,24 @@ static const char * const audio_clk_groups[] = {
 };
 
 static const char * const can0_groups[] = {
-       "can0_data_a",
+       "can0_data",
        "can0_data_b",
        "can0_data_c",
        "can0_data_d",
        "can0_data_e",
        "can0_data_f",
-       "can_clk_a",
+       "can_clk",
        "can_clk_b",
        "can_clk_c",
        "can_clk_d",
 };
 
 static const char * const can1_groups[] = {
-       "can1_data_a",
+       "can1_data",
        "can1_data_b",
        "can1_data_c",
        "can1_data_d",
-       "can_clk_a",
+       "can_clk",
        "can_clk_b",
        "can_clk_c",
        "can_clk_d",
index 172f26ce59ac9d2dbf5966a04490065a08ddbaa0..3bbcbf12c1fb7a88899762b417555b88ed08061d 100644 (file)
@@ -652,6 +652,25 @@ config TOSHIBA_BT_RFKILL
          If you have a modern Toshiba laptop with a Bluetooth and an
          RFKill switch (such as the Portege R500), say Y.
 
+config TOSHIBA_HAPS
+       tristate "Toshiba HDD Active Protection Sensor"
+       depends on ACPI
+       ---help---
+         This driver adds support for the built-in accelerometer
+         found on recent Toshiba laptops equiped with HID TOS620A
+         device.
+
+         This driver receives ACPI notify events 0x80 when the sensor
+         detects a sudden move or a harsh vibration, as well as an
+         ACPI notify event 0x81 whenever the movement or vibration has
+         been stabilized.
+
+         Also provides sysfs entries to get/set the desired protection
+         level and reseting the HDD protection interface.
+
+         If you have a recent Toshiba laptop with a built-in accelerometer
+         device, say Y.
+
 config ACPI_CMPC
        tristate "CMPC Laptop Extras"
        depends on X86 && ACPI
index c4ca428fd3db2651706171df439b24b52588e5c0..f82232b1fc4d719491ba5e2550603fed50802e51 100644 (file)
@@ -38,6 +38,7 @@ obj-$(CONFIG_TOPSTAR_LAPTOP)  += topstar-laptop.o
 obj-$(CONFIG_ACPI_TOSHIBA)     += toshiba_acpi.o
 
 obj-$(CONFIG_TOSHIBA_BT_RFKILL)        += toshiba_bluetooth.o
+obj-$(CONFIG_TOSHIBA_HAPS)     += toshiba_haps.o
 obj-$(CONFIG_INTEL_SCU_IPC)    += intel_scu_ipc.o
 obj-$(CONFIG_INTEL_SCU_IPC_UTIL) += intel_scu_ipcutil.o
 obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o
index bbf78b2d6d93f9f020729e3dd07ff210cb048404..96a0b75c52c9a6232c99b18e61751f3eb62e940a 100644 (file)
@@ -96,7 +96,7 @@ enum acer_wmi_event_ids {
        WMID_ACCEL_EVENT = 0x5,
 };
 
-static const struct key_entry acer_wmi_keymap[] = {
+static const struct key_entry acer_wmi_keymap[] __initconst = {
        {KE_KEY, 0x01, {KEY_WLAN} },     /* WiFi */
        {KE_KEY, 0x03, {KEY_WLAN} },     /* WiFi */
        {KE_KEY, 0x04, {KEY_WLAN} },     /* WiFi */
@@ -294,7 +294,7 @@ struct quirk_entry {
 
 static struct quirk_entry *quirks;
 
-static void set_quirks(void)
+static void __init set_quirks(void)
 {
        if (!interface)
                return;
@@ -306,7 +306,7 @@ static void set_quirks(void)
                interface->capability |= ACER_CAP_BRIGHTNESS;
 }
 
-static int dmi_matched(const struct dmi_system_id *dmi)
+static int __init dmi_matched(const struct dmi_system_id *dmi)
 {
        quirks = dmi->driver_data;
        return 1;
@@ -337,7 +337,7 @@ static struct quirk_entry quirk_lenovo_ideapad_s205 = {
 };
 
 /* The Aspire One has a dummy ACPI-WMI interface - disable it */
-static struct dmi_system_id acer_blacklist[] = {
+static const struct dmi_system_id acer_blacklist[] __initconst = {
        {
                .ident = "Acer Aspire One (SSD)",
                .matches = {
@@ -355,7 +355,7 @@ static struct dmi_system_id acer_blacklist[] = {
        {}
 };
 
-static struct dmi_system_id acer_quirks[] = {
+static const struct dmi_system_id acer_quirks[] __initconst = {
        {
                .callback = dmi_matched,
                .ident = "Acer Aspire 1360",
@@ -530,14 +530,15 @@ static struct dmi_system_id acer_quirks[] = {
        {}
 };
 
-static int video_set_backlight_video_vendor(const struct dmi_system_id *d)
+static int __init
+video_set_backlight_video_vendor(const struct dmi_system_id *d)
 {
        interface->capability &= ~ACER_CAP_BRIGHTNESS;
        pr_info("Brightness must be controlled by generic video driver\n");
        return 0;
 }
 
-static const struct dmi_system_id video_vendor_dmi_table[] = {
+static const struct dmi_system_id video_vendor_dmi_table[] __initconst = {
        {
                .callback = video_set_backlight_video_vendor,
                .ident = "Acer TravelMate 4750",
@@ -582,7 +583,7 @@ static const struct dmi_system_id video_vendor_dmi_table[] = {
 };
 
 /* Find which quirks are needed for a particular vendor/ model pair */
-static void find_quirks(void)
+static void __init find_quirks(void)
 {
        if (!force_series) {
                dmi_check_system(acer_quirks);
@@ -749,7 +750,7 @@ static acpi_status AMW0_set_u32(u32 value, u32 cap)
        return wmab_execute(&args, NULL);
 }
 
-static acpi_status AMW0_find_mailled(void)
+static acpi_status __init AMW0_find_mailled(void)
 {
        struct wmab_args args;
        struct wmab_ret ret;
@@ -781,16 +782,16 @@ static acpi_status AMW0_find_mailled(void)
        return AE_OK;
 }
 
-static int AMW0_set_cap_acpi_check_device_found;
+static int AMW0_set_cap_acpi_check_device_found __initdata;
 
-static acpi_status AMW0_set_cap_acpi_check_device_cb(acpi_handle handle,
+static acpi_status __init AMW0_set_cap_acpi_check_device_cb(acpi_handle handle,
        u32 level, void *context, void **retval)
 {
        AMW0_set_cap_acpi_check_device_found = 1;
        return AE_OK;
 }
 
-static const struct acpi_device_id norfkill_ids[] = {
+static const struct acpi_device_id norfkill_ids[] __initconst = {
        { "VPC2004", 0},
        { "IBM0068", 0},
        { "LEN0068", 0},
@@ -798,7 +799,7 @@ static const struct acpi_device_id norfkill_ids[] = {
        { "", 0},
 };
 
-static int AMW0_set_cap_acpi_check_device(void)
+static int __init AMW0_set_cap_acpi_check_device(void)
 {
        const struct acpi_device_id *id;
 
@@ -808,7 +809,7 @@ static int AMW0_set_cap_acpi_check_device(void)
        return AMW0_set_cap_acpi_check_device_found;
 }
 
-static acpi_status AMW0_set_capabilities(void)
+static acpi_status __init AMW0_set_capabilities(void)
 {
        struct wmab_args args;
        struct wmab_ret ret;
@@ -1184,7 +1185,7 @@ static acpi_status wmid_v2_set_u32(u32 value, u32 cap)
        return wmid3_set_device_status(value, device);
 }
 
-static void type_aa_dmi_decode(const struct dmi_header *header, void *dummy)
+static void __init type_aa_dmi_decode(const struct dmi_header *header, void *d)
 {
        struct hotkey_function_type_aa *type_aa;
 
@@ -1209,7 +1210,7 @@ static void type_aa_dmi_decode(const struct dmi_header *header, void *dummy)
        commun_fn_key_number = type_aa->commun_fn_key_number;
 }
 
-static acpi_status WMID_set_capabilities(void)
+static acpi_status __init WMID_set_capabilities(void)
 {
        struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
        union acpi_object *obj;
@@ -1658,7 +1659,7 @@ static ssize_t show_bool_threeg(struct device *dev,
        u32 result; \
        acpi_status status;
 
-       pr_info("This threeg sysfs will be removed in 2012 - used by: %s\n",
+       pr_info("This threeg sysfs will be removed in 2014 - used by: %s\n",
                current->comm);
        status = get_u32(&result, ACER_CAP_THREEG);
        if (ACPI_SUCCESS(status))
@@ -1671,7 +1672,7 @@ static ssize_t set_bool_threeg(struct device *dev,
 {
        u32 tmp = simple_strtoul(buf, NULL, 10);
        acpi_status status = set_u32(tmp, ACER_CAP_THREEG);
-       pr_info("This threeg sysfs will be removed in 2012 - used by: %s\n",
+       pr_info("This threeg sysfs will be removed in 2014 - used by: %s\n",
                current->comm);
        if (ACPI_FAILURE(status))
                return -EINVAL;
@@ -1683,7 +1684,7 @@ static DEVICE_ATTR(threeg, S_IRUGO | S_IWUSR, show_bool_threeg,
 static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
        char *buf)
 {
-       pr_info("This interface sysfs will be removed in 2012 - used by: %s\n",
+       pr_info("This interface sysfs will be removed in 2014 - used by: %s\n",
                current->comm);
        switch (interface->type) {
        case ACER_AMW0:
@@ -1777,7 +1778,7 @@ static void acer_wmi_notify(u32 value, void *context)
        }
 }
 
-static acpi_status
+static acpi_status __init
 wmid3_set_lm_mode(struct lm_input_params *params,
                  struct lm_return_value *return_value)
 {
@@ -1811,7 +1812,7 @@ wmid3_set_lm_mode(struct lm_input_params *params,
        return status;
 }
 
-static int acer_wmi_enable_ec_raw(void)
+static int __init acer_wmi_enable_ec_raw(void)
 {
        struct lm_return_value return_value;
        acpi_status status;
@@ -1834,7 +1835,7 @@ static int acer_wmi_enable_ec_raw(void)
        return status;
 }
 
-static int acer_wmi_enable_lm(void)
+static int __init acer_wmi_enable_lm(void)
 {
        struct lm_return_value return_value;
        acpi_status status;
@@ -2043,6 +2044,7 @@ static int acer_platform_remove(struct platform_device *device)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int acer_suspend(struct device *dev)
 {
        u32 value;
@@ -2083,6 +2085,10 @@ static int acer_resume(struct device *dev)
 
        return 0;
 }
+#else
+#define acer_suspend   NULL
+#define acer_resume    NULL
+#endif
 
 static SIMPLE_DEV_PM_OPS(acer_pm, acer_suspend, acer_resume);
 
@@ -2120,7 +2126,7 @@ static int remove_sysfs(struct platform_device *device)
        return 0;
 }
 
-static int create_sysfs(void)
+static int __init create_sysfs(void)
 {
        int retval = -ENOMEM;
 
@@ -2149,7 +2155,7 @@ static void remove_debugfs(void)
        debugfs_remove(interface->debug.root);
 }
 
-static int create_debugfs(void)
+static int __init create_debugfs(void)
 {
        interface->debug.root = debugfs_create_dir("acer-wmi", NULL);
        if (!interface->debug.root) {
index 297b6640213f3f7ab45139e835e2ae092517b31a..c5af23b64438514f3d6e95eed62303557be4ff34 100644 (file)
@@ -59,25 +59,33 @@ enum WMAX_CONTROL_STATES {
 
 struct quirk_entry {
        u8 num_zones;
+       u8 hdmi_mux;
 };
 
 static struct quirk_entry *quirks;
 
 static struct quirk_entry quirk_unknown = {
        .num_zones = 2,
+       .hdmi_mux = 0,
 };
 
 static struct quirk_entry quirk_x51_family = {
        .num_zones = 3,
+       .hdmi_mux = 0.
 };
 
-static int dmi_matched(const struct dmi_system_id *dmi)
+static struct quirk_entry quirk_asm100 = {
+       .num_zones = 2,
+       .hdmi_mux = 1,
+};
+
+static int __init dmi_matched(const struct dmi_system_id *dmi)
 {
        quirks = dmi->driver_data;
        return 1;
 }
 
-static struct dmi_system_id alienware_quirks[] = {
+static const struct dmi_system_id alienware_quirks[] __initconst = {
        {
         .callback = dmi_matched,
         .ident = "Alienware X51 R1",
@@ -96,6 +104,15 @@ static struct dmi_system_id alienware_quirks[] = {
                     },
         .driver_data = &quirk_x51_family,
         },
+       {
+               .callback = dmi_matched,
+               .ident = "Alienware ASM100",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "ASM100"),
+               },
+               .driver_data = &quirk_asm100,
+       },
        {}
 };
 
@@ -537,7 +554,8 @@ static struct attribute_group hdmi_attribute_group = {
 
 static void remove_hdmi(struct platform_device *dev)
 {
-       sysfs_remove_group(&dev->dev.kobj, &hdmi_attribute_group);
+       if (quirks->hdmi_mux > 0)
+               sysfs_remove_group(&dev->dev.kobj, &hdmi_attribute_group);
 }
 
 static int create_hdmi(struct platform_device *dev)
@@ -583,7 +601,7 @@ static int __init alienware_wmi_init(void)
        if (ret)
                goto fail_platform_device2;
 
-       if (interface == WMAX) {
+       if (quirks->hdmi_mux > 0) {
                ret = create_hdmi(platform_device);
                if (ret)
                        goto fail_prep_hdmi;
index ddf0eefd862c97b394e084b9433bb579d62c651b..3a4951f46065dc95abf7767572426566027e1381 100644 (file)
@@ -70,17 +70,35 @@ static struct quirk_entry quirk_asus_x55u = {
        .no_display_toggle = true,
 };
 
-static struct quirk_entry quirk_asus_x401u = {
+static struct quirk_entry quirk_asus_wapf4 = {
        .wapf = 4,
 };
 
+static struct quirk_entry quirk_asus_x200ca = {
+       .wapf = 2,
+};
+
 static int dmi_matched(const struct dmi_system_id *dmi)
 {
        quirks = dmi->driver_data;
        return 1;
 }
 
-static struct dmi_system_id asus_quirks[] = {
+static const struct dmi_system_id asus_quirks[] = {
+       {
+               .callback = dmi_matched,
+               .ident = "ASUSTeK COMPUTER INC. U32U",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "U32U"),
+               },
+               /*
+                * Note this machine has a Brazos APU, and most Brazos Asus
+                * machines need quirk_asus_x55u / wmi_backlight_power but
+                * here acpi-video seems to work fine for backlight control.
+                */
+               .driver_data = &quirk_asus_wapf4,
+       },
        {
                .callback = dmi_matched,
                .ident = "ASUSTeK COMPUTER INC. X401U",
@@ -97,7 +115,7 @@ static struct dmi_system_id asus_quirks[] = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
                        DMI_MATCH(DMI_PRODUCT_NAME, "X401A"),
                },
-               .driver_data = &quirk_asus_x401u,
+               .driver_data = &quirk_asus_wapf4,
        },
        {
                .callback = dmi_matched,
@@ -106,7 +124,7 @@ static struct dmi_system_id asus_quirks[] = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
                        DMI_MATCH(DMI_PRODUCT_NAME, "X401A1"),
                },
-               .driver_data = &quirk_asus_x401u,
+               .driver_data = &quirk_asus_wapf4,
        },
        {
                .callback = dmi_matched,
@@ -124,7 +142,7 @@ static struct dmi_system_id asus_quirks[] = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
                        DMI_MATCH(DMI_PRODUCT_NAME, "X501A"),
                },
-               .driver_data = &quirk_asus_x401u,
+               .driver_data = &quirk_asus_wapf4,
        },
        {
                .callback = dmi_matched,
@@ -133,7 +151,7 @@ static struct dmi_system_id asus_quirks[] = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
                        DMI_MATCH(DMI_PRODUCT_NAME, "X501A1"),
                },
-               .driver_data = &quirk_asus_x401u,
+               .driver_data = &quirk_asus_wapf4,
        },
        {
                .callback = dmi_matched,
@@ -142,7 +160,25 @@ static struct dmi_system_id asus_quirks[] = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
                        DMI_MATCH(DMI_PRODUCT_NAME, "X550CA"),
                },
-               .driver_data = &quirk_asus_x401u,
+               .driver_data = &quirk_asus_wapf4,
+       },
+       {
+               .callback = dmi_matched,
+               .ident = "ASUSTeK COMPUTER INC. X550CC",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "X550CC"),
+               },
+               .driver_data = &quirk_asus_wapf4,
+       },
+       {
+               .callback = dmi_matched,
+               .ident = "ASUSTeK COMPUTER INC. X550CL",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "X550CL"),
+               },
+               .driver_data = &quirk_asus_wapf4,
        },
        {
                .callback = dmi_matched,
@@ -151,7 +187,7 @@ static struct dmi_system_id asus_quirks[] = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
                        DMI_MATCH(DMI_PRODUCT_NAME, "X55A"),
                },
-               .driver_data = &quirk_asus_x401u,
+               .driver_data = &quirk_asus_wapf4,
        },
        {
                .callback = dmi_matched,
@@ -160,7 +196,7 @@ static struct dmi_system_id asus_quirks[] = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
                        DMI_MATCH(DMI_PRODUCT_NAME, "X55C"),
                },
-               .driver_data = &quirk_asus_x401u,
+               .driver_data = &quirk_asus_wapf4,
        },
        {
                .callback = dmi_matched,
@@ -178,7 +214,7 @@ static struct dmi_system_id asus_quirks[] = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
                        DMI_MATCH(DMI_PRODUCT_NAME, "X55VD"),
                },
-               .driver_data = &quirk_asus_x401u,
+               .driver_data = &quirk_asus_wapf4,
        },
        {
                .callback = dmi_matched,
@@ -187,7 +223,16 @@ static struct dmi_system_id asus_quirks[] = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
                        DMI_MATCH(DMI_PRODUCT_NAME, "X75A"),
                },
-               .driver_data = &quirk_asus_x401u,
+               .driver_data = &quirk_asus_wapf4,
+       },
+       {
+               .callback = dmi_matched,
+               .ident = "ASUSTeK COMPUTER INC. X75VBP",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "X75VBP"),
+               },
+               .driver_data = &quirk_asus_wapf4,
        },
        {
                .callback = dmi_matched,
@@ -196,7 +241,7 @@ static struct dmi_system_id asus_quirks[] = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
                        DMI_MATCH(DMI_PRODUCT_NAME, "1015E"),
                },
-               .driver_data = &quirk_asus_x401u,
+               .driver_data = &quirk_asus_wapf4,
        },
        {
                .callback = dmi_matched,
@@ -205,7 +250,16 @@ static struct dmi_system_id asus_quirks[] = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
                        DMI_MATCH(DMI_PRODUCT_NAME, "1015U"),
                },
-               .driver_data = &quirk_asus_x401u,
+               .driver_data = &quirk_asus_wapf4,
+       },
+       {
+               .callback = dmi_matched,
+               .ident = "ASUSTeK COMPUTER INC. X200CA",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "X200CA"),
+               },
+               .driver_data = &quirk_asus_x200ca,
        },
        {},
 };
index 3c6ccedc82b6239fdee1bfb6925e0e3b032142c4..21fc932da3a1461d35697cc2ee2c78085128b434 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/platform_device.h>
 #include <linux/thermal.h>
 #include <linux/acpi.h>
+#include <linux/dmi.h>
 #include <acpi/video.h>
 
 #include "asus-wmi.h"
@@ -554,7 +555,7 @@ static int asus_wmi_led_init(struct asus_wmi *asus)
                        goto error;
        }
 
-       if (wlan_led_presence(asus) && (asus->driver->quirks->wapf == 4)) {
+       if (wlan_led_presence(asus) && (asus->driver->quirks->wapf > 0)) {
                INIT_WORK(&asus->wlan_led_work, wlan_led_update);
 
                asus->wlan_led.name = "asus::wlan";
@@ -884,7 +885,7 @@ static int asus_new_rfkill(struct asus_wmi *asus,
                return -EINVAL;
 
        if ((dev_id == ASUS_WMI_DEVID_WLAN) &&
-                       (asus->driver->quirks->wapf == 4))
+                       (asus->driver->quirks->wapf > 0))
                rfkill_set_led_trigger_name(*rfkill, "asus-wlan");
 
        rfkill_init_sw_state(*rfkill, !result);
@@ -1270,10 +1271,7 @@ static int asus_wmi_backlight_init(struct asus_wmi *asus)
        int power;
 
        max = read_brightness_max(asus);
-
-       if (max == -ENODEV)
-               max = 0;
-       else if (max < 0)
+       if (max < 0)
                return max;
 
        power = read_backlight_power(asus);
@@ -1734,6 +1732,7 @@ static int asus_wmi_add(struct platform_device *pdev)
        struct platform_driver *pdrv = to_platform_driver(pdev->dev.driver);
        struct asus_wmi_driver *wdrv = to_asus_wmi_driver(pdrv);
        struct asus_wmi *asus;
+       const char *chassis_type;
        acpi_status status;
        int err;
        u32 result;
@@ -1770,6 +1769,11 @@ static int asus_wmi_add(struct platform_device *pdev)
        if (err)
                goto fail_rfkill;
 
+       /* Some Asus desktop boards export an acpi-video backlight interface,
+          stop this from showing up */
+       chassis_type = dmi_get_system_info(DMI_CHASSIS_TYPE);
+       if (chassis_type && !strcmp(chassis_type, "3"))
+               acpi_video_dmi_promote_vendor();
        if (asus->driver->quirks->wmi_backlight_power)
                acpi_video_dmi_promote_vendor();
        if (!acpi_video_backlight_support()) {
index 7297df2ebf503771d080a3467869819d72921b08..26bfd7bb5c1350822b23bb6814dd6784738d91b1 100644 (file)
@@ -1028,7 +1028,7 @@ static int compal_probe(struct platform_device *pdev)
                return err;
 
        hwmon_dev = hwmon_device_register_with_groups(&pdev->dev,
-                                                     DRIVER_NAME, data,
+                                                     "compal", data,
                                                      compal_hwmon_groups);
        if (IS_ERR(hwmon_dev)) {
                err = PTR_ERR(hwmon_dev);
index fed4111ac31a6d6fbff0c02a6be563485ccec7dc..233d2ee598a62cdb5c1b05cc0ef77737cb48f98a 100644 (file)
@@ -70,7 +70,7 @@ static struct quirk_entry quirk_dell_vostro_v130 = {
        .touchpad_led = 1,
 };
 
-static int dmi_matched(const struct dmi_system_id *dmi)
+static int __init dmi_matched(const struct dmi_system_id *dmi)
 {
        quirks = dmi->driver_data;
        return 1;
@@ -123,7 +123,7 @@ static const struct dmi_system_id dell_device_table[] __initconst = {
 };
 MODULE_DEVICE_TABLE(dmi, dell_device_table);
 
-static struct dmi_system_id dell_quirks[] = {
+static const struct dmi_system_id dell_quirks[] __initconst = {
        {
                .callback = dmi_matched,
                .ident = "Dell Vostro V130",
@@ -780,7 +780,7 @@ static struct led_classdev touchpad_led = {
        .flags = LED_CORE_SUSPENDRESUME,
 };
 
-static int touchpad_led_init(struct device *dev)
+static int __init touchpad_led_init(struct device *dev)
 {
        return led_classdev_register(dev, &touchpad_led);
 }
index 9b0c57cd1d4a8a9d3c89e8a3aa2e3d1b9758f137..bd533c22be570a736795b2a35a83a7439a1d76d5 100644 (file)
@@ -1053,20 +1053,20 @@ static ssize_t show_sys_hwmon(int (*get)(void), char *buf)
        return sprintf(buf, "%d\n", get());
 }
 
-#define EEEPC_CREATE_SENSOR_ATTR(_name, _mode, _set, _get)             \
+#define EEEPC_CREATE_SENSOR_ATTR(_name, _mode, _get, _set)             \
        static ssize_t show_##_name(struct device *dev,                 \
                                    struct device_attribute *attr,      \
                                    char *buf)                          \
        {                                                               \
-               return show_sys_hwmon(_set, buf);                       \
+               return show_sys_hwmon(_get, buf);                       \
        }                                                               \
        static ssize_t store_##_name(struct device *dev,                \
                                     struct device_attribute *attr,     \
                                     const char *buf, size_t count)     \
        {                                                               \
-               return store_sys_hwmon(_get, buf, count);               \
+               return store_sys_hwmon(_set, buf, count);               \
        }                                                               \
-       static DEVICE_ATTR(_name, _mode, show_##_name, store_##_name);
+       static DEVICE_ATTR(_name, _mode, show_##_name, store_##_name)
 
 EEEPC_CREATE_SENSOR_ATTR(fan1_input, S_IRUGO, eeepc_get_fan_rpm, NULL);
 EEEPC_CREATE_SENSOR_ATTR(pwm1, S_IRUGO | S_IWUSR,
index 6112933f627834cc1c4561feb68a3edc28492e5e..14fd2ecb06a10de7770c38cadba11091e70be21b 100644 (file)
@@ -145,7 +145,7 @@ static int dmi_matched(const struct dmi_system_id *dmi)
        return 1;
 }
 
-static struct dmi_system_id asus_quirks[] = {
+static const struct dmi_system_id asus_quirks[] = {
        {
                .callback = dmi_matched,
                .ident = "ASUSTeK Computer INC. 1000H",
index e6f336270c2191fd9cd1418f869b5aa4dcc499de..87aa28c4280fe815fa488006c814e026c1c99350 100644 (file)
 #define FUJLAPTOP_DBG_INFO       0x0004
 #define FUJLAPTOP_DBG_TRACE      0x0008
 
-#define dbg_printk(a_dbg_level, format, arg...) \
+#ifdef CONFIG_FUJITSU_LAPTOP_DEBUG
+#define vdbg_printk(a_dbg_level, format, arg...) \
        do { if (dbg_level & a_dbg_level) \
                printk(FUJLAPTOP_DEBUG "%s: " format, __func__ , ## arg); \
        } while (0)
-#ifdef CONFIG_FUJITSU_LAPTOP_DEBUG
-#define vdbg_printk(a_dbg_level, format, arg...) \
-       dbg_printk(a_dbg_level, format, ## arg)
 #else
-#define vdbg_printk(a_dbg_level, format, arg...)
+#define vdbg_printk(a_dbg_level, format, arg...) \
+       do { } while (0)
 #endif
 
 /* Device controlling the backlight and associated keys */
@@ -564,7 +563,7 @@ static struct platform_driver fujitsupf_driver = {
                   }
 };
 
-static void dmi_check_cb_common(const struct dmi_system_id *id)
+static void __init dmi_check_cb_common(const struct dmi_system_id *id)
 {
        pr_info("Identified laptop model '%s'\n", id->ident);
        if (use_alt_lcd_levels == -1) {
@@ -578,7 +577,7 @@ static void dmi_check_cb_common(const struct dmi_system_id *id)
        }
 }
 
-static int dmi_check_cb_s6410(const struct dmi_system_id *id)
+static int __init dmi_check_cb_s6410(const struct dmi_system_id *id)
 {
        dmi_check_cb_common(id);
        fujitsu->keycode1 = KEY_SCREENLOCK;     /* "Lock" */
@@ -586,7 +585,7 @@ static int dmi_check_cb_s6410(const struct dmi_system_id *id)
        return 1;
 }
 
-static int dmi_check_cb_s6420(const struct dmi_system_id *id)
+static int __init dmi_check_cb_s6420(const struct dmi_system_id *id)
 {
        dmi_check_cb_common(id);
        fujitsu->keycode1 = KEY_SCREENLOCK;     /* "Lock" */
@@ -594,7 +593,7 @@ static int dmi_check_cb_s6420(const struct dmi_system_id *id)
        return 1;
 }
 
-static int dmi_check_cb_p8010(const struct dmi_system_id *id)
+static int __init dmi_check_cb_p8010(const struct dmi_system_id *id)
 {
        dmi_check_cb_common(id);
        fujitsu->keycode1 = KEY_HELP;   /* "Support" */
@@ -603,7 +602,7 @@ static int dmi_check_cb_p8010(const struct dmi_system_id *id)
        return 1;
 }
 
-static struct dmi_system_id fujitsu_dmi_table[] = {
+static const struct dmi_system_id fujitsu_dmi_table[] __initconst = {
        {
         .ident = "Fujitsu Siemens S6410",
         .matches = {
index c3784baceae3cca2b9d1d32113016f4562f94e48..53bdbb01bd3f375508e888fe43c726127f44ff45 100644 (file)
@@ -315,21 +315,21 @@ static irqreturn_t fujitsu_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static void fujitsu_dmi_common(const struct dmi_system_id *dmi)
+static void __init fujitsu_dmi_common(const struct dmi_system_id *dmi)
 {
        pr_info("%s\n", dmi->ident);
        memcpy(fujitsu.config.keymap, dmi->driver_data,
                        sizeof(fujitsu.config.keymap));
 }
 
-static int fujitsu_dmi_lifebook(const struct dmi_system_id *dmi)
+static int __init fujitsu_dmi_lifebook(const struct dmi_system_id *dmi)
 {
        fujitsu_dmi_common(dmi);
        fujitsu.config.quirks |= INVERT_TABLET_MODE_BIT;
        return 1;
 }
 
-static int fujitsu_dmi_stylistic(const struct dmi_system_id *dmi)
+static int __init fujitsu_dmi_stylistic(const struct dmi_system_id *dmi)
 {
        fujitsu_dmi_common(dmi);
        fujitsu.config.quirks |= FORCE_TABLET_MODE_IF_UNDOCK;
index 484a8673b835d17fa2ef4eb3eea2e6853be08b24..4c559640dcbaf4bf0be8eb1e349dc3e5fa567e47 100644 (file)
@@ -295,7 +295,7 @@ static int hp_wmi_tablet_state(void)
        return (state & 0x4) ? 1 : 0;
 }
 
-static int hp_wmi_bios_2009_later(void)
+static int __init hp_wmi_bios_2009_later(void)
 {
        int state = 0;
        int ret = hp_wmi_perform_query(HPWMI_FEATURE_QUERY, 0, &state,
@@ -704,7 +704,7 @@ static void cleanup_sysfs(struct platform_device *device)
        device_remove_file(&device->dev, &dev_attr_postcode);
 }
 
-static int hp_wmi_rfkill_setup(struct platform_device *device)
+static int __init hp_wmi_rfkill_setup(struct platform_device *device)
 {
        int err;
        int wireless = 0;
@@ -806,7 +806,7 @@ register_wifi_error:
        return err;
 }
 
-static int hp_wmi_rfkill2_setup(struct platform_device *device)
+static int __init hp_wmi_rfkill2_setup(struct platform_device *device)
 {
        int err, i;
        struct bios_rfkill2_state state;
index 3dc934438c28f9082144ded5f346f39e3716f4db..13e14ec1d3d7118c4e4ab63ac98a2ef0c1258118 100644 (file)
@@ -74,7 +74,7 @@ static inline void delayed_sysfs_set(struct led_classdev *led_cdev,
 /* HP-specific accelerometer driver ------------------------------------ */
 
 /* For automatic insertion of the module */
-static struct acpi_device_id lis3lv02d_device_ids[] = {
+static const struct acpi_device_id lis3lv02d_device_ids[] = {
        {"HPQ0004", 0}, /* HP Mobile Data Protection System PNP */
        {"HPQ6000", 0}, /* HP Mobile Data Protection System PNP */
        {"HPQ6007", 0}, /* HP Mobile Data Protection System PNP */
@@ -192,7 +192,7 @@ DEFINE_CONV(xy_swap_yz_inverted, 2, -1, -3);
        },                                              \
        .driver_data = &lis3lv02d_axis_##_axis          \
 }
-static struct dmi_system_id lis3lv02d_dmi_ids[] = {
+static const struct dmi_system_id lis3lv02d_dmi_ids[] = {
        /* product names are truncated to match all kinds of a same model */
        AXIS_DMI_MATCH("NC64x0", "HP Compaq nc64", x_inverted),
        AXIS_DMI_MATCH("NC84x0", "HP Compaq nc84", z_inverted),
index b4c495a62eeca14be5bc0c7a191786deafec205c..02152de135b5c43b79318c6c5ac7971f0723e478 100644 (file)
@@ -87,6 +87,7 @@ struct ideapad_private {
        struct backlight_device *blightdev;
        struct dentry *debug;
        unsigned long cfg;
+       bool has_hw_rfkill_switch;
 };
 
 static bool no_bt_rfkill;
@@ -439,7 +440,7 @@ static umode_t ideapad_is_visible(struct kobject *kobj,
        return supported ? attr->mode : 0;
 }
 
-static struct attribute_group ideapad_attribute_group = {
+static const struct attribute_group ideapad_attribute_group = {
        .is_visible = ideapad_is_visible,
        .attrs = ideapad_attributes
 };
@@ -454,7 +455,7 @@ struct ideapad_rfk_data {
        int type;
 };
 
-const struct ideapad_rfk_data ideapad_rfk_data[] = {
+static const struct ideapad_rfk_data ideapad_rfk_data[] = {
        { "ideapad_wlan",    CFG_WIFI_BIT, VPCCMD_W_WIFI, RFKILL_TYPE_WLAN },
        { "ideapad_bluetooth", CFG_BT_BIT, VPCCMD_W_BT, RFKILL_TYPE_BLUETOOTH },
        { "ideapad_3g",        CFG_3G_BIT, VPCCMD_W_3G, RFKILL_TYPE_WWAN },
@@ -473,12 +474,14 @@ static struct rfkill_ops ideapad_rfk_ops = {
 
 static void ideapad_sync_rfk_state(struct ideapad_private *priv)
 {
-       unsigned long hw_blocked;
+       unsigned long hw_blocked = 0;
        int i;
 
-       if (read_ec_data(priv->adev->handle, VPCCMD_R_RF, &hw_blocked))
-               return;
-       hw_blocked = !hw_blocked;
+       if (priv->has_hw_rfkill_switch) {
+               if (read_ec_data(priv->adev->handle, VPCCMD_R_RF, &hw_blocked))
+                       return;
+               hw_blocked = !hw_blocked;
+       }
 
        for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
                if (priv->rfk[i])
@@ -821,14 +824,17 @@ static void ideapad_acpi_notify(acpi_handle handle, u32 event, void *data)
        }
 }
 
-/* Blacklist for devices where the ideapad rfkill interface does not work */
-static struct dmi_system_id rfkill_blacklist[] = {
-       /* The Lenovo Yoga 2 11 always reports everything as blocked */
+/*
+ * Some ideapads don't have a hardware rfkill switch, reading VPCCMD_R_RF
+ * always results in 0 on these models, causing ideapad_laptop to wrongly
+ * report all radios as hardware-blocked.
+ */
+static const struct dmi_system_id no_hw_rfkill_list[] = {
        {
-               .ident = "Lenovo Yoga 2 11",
+               .ident = "Lenovo Yoga 2 11 / 13 / Pro",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Yoga 2 11"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Yoga 2"),
                },
        },
        {}
@@ -856,6 +862,7 @@ static int ideapad_acpi_add(struct platform_device *pdev)
        priv->cfg = cfg;
        priv->adev = adev;
        priv->platform_device = pdev;
+       priv->has_hw_rfkill_switch = !dmi_check_system(no_hw_rfkill_list);
 
        ret = ideapad_sysfs_init(priv);
        if (ret)
@@ -869,11 +876,17 @@ static int ideapad_acpi_add(struct platform_device *pdev)
        if (ret)
                goto input_failed;
 
-       if (!dmi_check_system(rfkill_blacklist)) {
-               for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
-                       if (test_bit(ideapad_rfk_data[i].cfgbit, &priv->cfg))
-                               ideapad_register_rfkill(priv, i);
-       }
+       /*
+        * On some models without a hw-switch (the yoga 2 13 at least)
+        * VPCCMD_W_RF must be explicitly set to 1 for the wifi to work.
+        */
+       if (!priv->has_hw_rfkill_switch)
+               write_ec_cmd(priv->adev->handle, VPCCMD_W_RF, 1);
+
+       for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
+               if (test_bit(ideapad_rfk_data[i].cfgbit, &priv->cfg))
+                       ideapad_register_rfkill(priv, i);
+
        ideapad_sync_rfk_state(priv);
        ideapad_sync_touchpad_state(priv);
 
index a0d1f576cf406e0c292982ca1b29a40ae58f870b..c0242ed13d9eb8127d0056c22b62186367d5581a 100644 (file)
@@ -269,7 +269,7 @@ struct ips_mcp_limits {
 
 /* Max temps are -10 degrees C to avoid PROCHOT# */
 
-struct ips_mcp_limits ips_sv_limits = {
+static struct ips_mcp_limits ips_sv_limits = {
        .mcp_power_limit = 35000,
        .core_power_limit = 29000,
        .mch_power_limit = 20000,
@@ -277,7 +277,7 @@ struct ips_mcp_limits ips_sv_limits = {
        .mch_temp_limit = 90
 };
 
-struct ips_mcp_limits ips_lv_limits = {
+static struct ips_mcp_limits ips_lv_limits = {
        .mcp_power_limit = 25000,
        .core_power_limit = 21000,
        .mch_power_limit = 13000,
@@ -285,7 +285,7 @@ struct ips_mcp_limits ips_lv_limits = {
        .mch_temp_limit = 90
 };
 
-struct ips_mcp_limits ips_ulv_limits = {
+static struct ips_mcp_limits ips_ulv_limits = {
        .mcp_power_limit = 18000,
        .core_power_limit = 14000,
        .mch_power_limit = 11000,
index 9c5a07417b2b4a1e39c68a5998d972bc31e8eda0..26ad9ff12ac59f3dee03495a2e01f9b5489fc808 100644 (file)
@@ -2389,7 +2389,7 @@ static int sony_nc_lid_resume_setup(struct platform_device *pd,
                lid_ctl->attrs[LID_RESUME_S3].store = sony_nc_lid_resume_store;
        }
        for (i = 0; i < LID_RESUME_MAX &&
-                       lid_ctl->attrs[LID_RESUME_S3].attr.name; i++) {
+                       lid_ctl->attrs[i].attr.name; i++) {
                result = device_create_file(&pd->dev, &lid_ctl->attrs[i]);
                if (result)
                        goto liderror;
index d82f196e3cfe7044266b0d022a48f8866fa1dc5a..3bbc6eb60de56d5ebb55daa80b183f8296520325 100644 (file)
@@ -3174,7 +3174,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
                KEY_UNKNOWN,
 
                /* Extra keys in use since the X240 / T440 / T540 */
-               KEY_CONFIG, KEY_SEARCH, KEY_SCALE, KEY_COMPUTER,
+               KEY_CONFIG, KEY_SEARCH, KEY_SCALE, KEY_FILE,
                },
        };
 
@@ -6144,7 +6144,7 @@ static int brightness_set(unsigned int value)
 {
        int res;
 
-       if (value > bright_maxlvl || value < 0)
+       if (value > bright_maxlvl)
                return -EINVAL;
 
        vdbg_printk(TPACPI_DBG_BRGHT,
@@ -6860,7 +6860,7 @@ static int volume_alsa_mute_put(struct snd_kcontrol *kcontrol,
        return volume_alsa_set_mute(!ucontrol->value.integer.value[0]);
 }
 
-static struct snd_kcontrol_new volume_alsa_control_vol = {
+static struct snd_kcontrol_new volume_alsa_control_vol __initdata = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
        .name = "Console Playback Volume",
        .index = 0,
@@ -6869,7 +6869,7 @@ static struct snd_kcontrol_new volume_alsa_control_vol = {
        .get = volume_alsa_vol_get,
 };
 
-static struct snd_kcontrol_new volume_alsa_control_mute = {
+static struct snd_kcontrol_new volume_alsa_control_mute __initdata = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
        .name = "Console Playback Switch",
        .index = 0,
index 76441dcbe5ffcd83abbecbedbfd91852b5301c67..d0dce734b2edb37e055d6f30f6901a234645708f 100644 (file)
@@ -222,6 +222,12 @@ static const struct dmi_system_id toshiba_alt_keymap_dmi[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "Satellite M840"),
                },
        },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Qosmio X75-A"),
+               },
+       },
        {}
 };
 
@@ -229,6 +235,7 @@ static const struct key_entry toshiba_acpi_alt_keymap[] = {
        { KE_KEY, 0x157, { KEY_MUTE } },
        { KE_KEY, 0x102, { KEY_ZOOMOUT } },
        { KE_KEY, 0x103, { KEY_ZOOMIN } },
+       { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } },
        { KE_KEY, 0x139, { KEY_ZOOMRESET } },
        { KE_KEY, 0x13e, { KEY_SWITCHVIDEOMODE } },
        { KE_KEY, 0x13c, { KEY_BRIGHTNESSDOWN } },
@@ -872,7 +879,9 @@ static int lcd_proc_open(struct inode *inode, struct file *file)
 
 static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value)
 {
-       u32 hci_result;
+       u32 in[HCI_WORDS] = { HCI_SET, HCI_LCD_BRIGHTNESS, 0, 0, 0, 0 };
+       u32 out[HCI_WORDS];
+       acpi_status status;
 
        if (dev->tr_backlight_supported) {
                bool enable = !value;
@@ -883,9 +892,20 @@ static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value)
                        value--;
        }
 
-       value = value << HCI_LCD_BRIGHTNESS_SHIFT;
-       hci_write1(dev, HCI_LCD_BRIGHTNESS, value, &hci_result);
-       return hci_result == HCI_SUCCESS ? 0 : -EIO;
+       in[2] = value << HCI_LCD_BRIGHTNESS_SHIFT;
+       status = hci_raw(dev, in, out);
+       if (ACPI_FAILURE(status) || out[0] == HCI_FAILURE) {
+               pr_err("ACPI call to set brightness failed");
+               return -EIO;
+       }
+       /* Extra check for "incomplete" backlight method, where the AML code
+        * doesn't check for HCI_SET or HCI_GET and returns HCI_SUCCESS,
+        * the actual brightness, and in some cases the max brightness.
+        */
+       if (out[2] > 0  || out[3] == 0xE000)
+               return -ENODEV;
+
+       return out[0] == HCI_SUCCESS ? 0 : -EIO;
 }
 
 static int set_lcd_status(struct backlight_device *bd)
@@ -1235,10 +1255,15 @@ static ssize_t toshiba_kbd_bl_mode_store(struct device *dev,
                                         const char *buf, size_t count)
 {
        struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
-       int mode = -1;
-       int time = -1;
+       int mode;
+       int time;
+       int ret;
+
 
-       if (sscanf(buf, "%i", &mode) != 1 && (mode != 2 || mode != 1))
+       ret = kstrtoint(buf, 0, &mode);
+       if (ret)
+               return ret;
+       if (mode != SCI_KBD_MODE_FNZ && mode != SCI_KBD_MODE_AUTO)
                return -EINVAL;
 
        /* Set the Keyboard Backlight Mode where:
@@ -1246,11 +1271,12 @@ static ssize_t toshiba_kbd_bl_mode_store(struct device *dev,
         *      Auto - KBD backlight turns off automatically in given time
         *      FN-Z - KBD backlight "toggles" when hotkey pressed
         */
-       if (mode != -1 && toshiba->kbd_mode != mode) {
+       if (toshiba->kbd_mode != mode) {
                time = toshiba->kbd_time << HCI_MISC_SHIFT;
                time = time + toshiba->kbd_mode;
-               if (toshiba_kbd_illum_status_set(toshiba, time) < 0)
-                       return -EIO;
+               ret = toshiba_kbd_illum_status_set(toshiba, time);
+               if (ret)
+                       return ret;
                toshiba->kbd_mode = mode;
        }
 
@@ -1837,9 +1863,16 @@ static int toshiba_acpi_resume(struct device *device)
 {
        struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device));
        u32 result;
+       acpi_status status;
+
+       if (dev->hotkey_dev) {
+               status = acpi_evaluate_object(dev->acpi_dev->handle, "ENAB",
+                               NULL, NULL);
+               if (ACPI_FAILURE(status))
+                       pr_info("Unable to re-enable hotkeys\n");
 
-       if (dev->hotkey_dev)
                hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE, &result);
+       }
 
        return 0;
 }
diff --git a/drivers/platform/x86/toshiba_haps.c b/drivers/platform/x86/toshiba_haps.c
new file mode 100644 (file)
index 0000000..65300b6
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * Toshiba HDD Active Protection Sensor (HAPS) driver
+ *
+ * Copyright (C) 2014 Azael Avalos <coproscefalo@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/acpi.h>
+
+MODULE_AUTHOR("Azael Avalos <coproscefalo@gmail.com>");
+MODULE_DESCRIPTION("Toshiba HDD Active Protection Sensor");
+MODULE_LICENSE("GPL");
+
+struct toshiba_haps_dev {
+       struct acpi_device *acpi_dev;
+
+       int protection_level;
+};
+
+static struct toshiba_haps_dev *toshiba_haps;
+
+/* HAPS functions */
+static int toshiba_haps_reset_protection(acpi_handle handle)
+{
+       acpi_status status;
+
+       status = acpi_evaluate_object(handle, "RSSS", NULL, NULL);
+       if (ACPI_FAILURE(status)) {
+               pr_err("Unable to reset the HDD protection\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int toshiba_haps_protection_level(acpi_handle handle, int level)
+{
+       acpi_status status;
+
+       status = acpi_execute_simple_method(handle, "PTLV", level);
+       if (ACPI_FAILURE(status)) {
+               pr_err("Error while setting the protection level\n");
+               return -EIO;
+       }
+
+       pr_info("HDD protection level set to: %d\n", level);
+
+       return 0;
+}
+
+/* sysfs files */
+static ssize_t protection_level_show(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
+{
+       struct toshiba_haps_dev *haps = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%i\n", haps->protection_level);
+}
+
+static ssize_t protection_level_store(struct device *dev,
+                                     struct device_attribute *attr,
+                                     const char *buf, size_t count)
+{
+       struct toshiba_haps_dev *haps = dev_get_drvdata(dev);
+       int level, ret;
+
+       if (sscanf(buf, "%d", &level) != 1 || level < 0 || level > 3)
+               return -EINVAL;
+
+       /* Set the sensor level.
+        * Acceptable levels are:
+        * 0 - Disabled | 1 - Low | 2 - Medium | 3 - High
+        */
+       ret = toshiba_haps_protection_level(haps->acpi_dev->handle, level);
+       if (ret != 0)
+               return ret;
+
+       haps->protection_level = level;
+
+       return count;
+}
+
+static ssize_t reset_protection_store(struct device *dev,
+                                     struct device_attribute *attr,
+                                     const char *buf, size_t count)
+{
+       struct toshiba_haps_dev *haps = dev_get_drvdata(dev);
+       int reset, ret;
+
+       if (sscanf(buf, "%d", &reset) != 1 || reset != 1)
+               return -EINVAL;
+
+       /* Reset the protection interface */
+       ret = toshiba_haps_reset_protection(haps->acpi_dev->handle);
+       if (ret != 0)
+               return ret;
+
+       return count;
+}
+
+static DEVICE_ATTR(protection_level, S_IRUGO | S_IWUSR,
+                  protection_level_show, protection_level_store);
+static DEVICE_ATTR(reset_protection, S_IWUSR, NULL, reset_protection_store);
+
+static struct attribute *haps_attributes[] = {
+       &dev_attr_protection_level.attr,
+       &dev_attr_reset_protection.attr,
+       NULL,
+};
+
+static struct attribute_group haps_attr_group = {
+       .attrs = haps_attributes,
+};
+
+/*
+ * ACPI stuff
+ */
+static void toshiba_haps_notify(struct acpi_device *device, u32 event)
+{
+       pr_info("Received event: 0x%x", event);
+
+       acpi_bus_generate_netlink_event(device->pnp.device_class,
+                                       dev_name(&device->dev),
+                                       event, 0);
+}
+
+static int toshiba_haps_remove(struct acpi_device *device)
+{
+       sysfs_remove_group(&device->dev.kobj, &haps_attr_group);
+
+       if (toshiba_haps)
+               toshiba_haps = NULL;
+
+       return 0;
+}
+
+/* Helper function */
+static int toshiba_haps_available(acpi_handle handle)
+{
+       acpi_status status;
+       u64 hdd_present;
+
+       /*
+        * A non existent device as well as having (only)
+        * Solid State Drives can cause the call to fail.
+        */
+       status = acpi_evaluate_integer(handle, "_STA", NULL,
+                                      &hdd_present);
+       if (ACPI_FAILURE(status) || !hdd_present) {
+               pr_info("HDD protection not available or using SSD\n");
+               return 0;
+       }
+
+       return 1;
+}
+
+static int toshiba_haps_add(struct acpi_device *acpi_dev)
+{
+       struct toshiba_haps_dev *haps;
+       int ret;
+
+       if (toshiba_haps)
+               return -EBUSY;
+
+       if (!toshiba_haps_available(acpi_dev->handle))
+               return -ENODEV;
+
+       pr_info("Toshiba HDD Active Protection Sensor device\n");
+
+       haps = kzalloc(sizeof(struct toshiba_haps_dev), GFP_KERNEL);
+       if (!haps)
+               return -ENOMEM;
+
+       haps->acpi_dev = acpi_dev;
+       haps->protection_level = 2;
+       acpi_dev->driver_data = haps;
+       dev_set_drvdata(&acpi_dev->dev, haps);
+
+       /* Set the protection level, currently at level 2 (Medium) */
+       ret = toshiba_haps_protection_level(acpi_dev->handle, 2);
+       if (ret != 0)
+               return ret;
+
+       ret = sysfs_create_group(&acpi_dev->dev.kobj, &haps_attr_group);
+       if (ret)
+               return ret;
+
+       toshiba_haps = haps;
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int toshiba_haps_suspend(struct device *device)
+{
+       struct toshiba_haps_dev *haps;
+       int ret;
+
+       haps = acpi_driver_data(to_acpi_device(device));
+
+       /* Deactivate the protection on suspend */
+       ret = toshiba_haps_protection_level(haps->acpi_dev->handle, 0);
+
+       return ret;
+}
+
+static int toshiba_haps_resume(struct device *device)
+{
+       struct toshiba_haps_dev *haps;
+       int ret;
+
+       haps = acpi_driver_data(to_acpi_device(device));
+
+       /* Set the stored protection level */
+       ret = toshiba_haps_protection_level(haps->acpi_dev->handle,
+                                           haps->protection_level);
+
+       /* Reset the protection on resume */
+       ret = toshiba_haps_reset_protection(haps->acpi_dev->handle);
+       if (ret != 0)
+               return ret;
+
+       return ret;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(toshiba_haps_pm,
+                        toshiba_haps_suspend, toshiba_haps_resume);
+
+static const struct acpi_device_id haps_device_ids[] = {
+       {"TOS620A", 0},
+       {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, haps_device_ids);
+
+static struct acpi_driver toshiba_haps_driver = {
+       .name = "Toshiba HAPS",
+       .owner = THIS_MODULE,
+       .ids = haps_device_ids,
+       .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
+       .ops = {
+               .add =          toshiba_haps_add,
+               .remove =       toshiba_haps_remove,
+               .notify =       toshiba_haps_notify,
+       },
+       .drv.pm = &toshiba_haps_pm,
+};
+
+module_acpi_driver(toshiba_haps_driver);
index 43d13295e63d53a50b62dae995d3a63b7e112a3a..737e56d46f61950826419bbef2d9fb66d69abcc1 100644 (file)
@@ -256,10 +256,6 @@ static acpi_status wmi_method_enable(struct wmi_block *wblock, int enable)
        block = &wblock->gblock;
        handle = wblock->handle;
 
-       if (!block)
-               return AE_NOT_EXIST;
-
-
        snprintf(method, 5, "WE%02X", block->notify_id);
        status = acpi_execute_simple_method(handle, method, enable);
 
index b1cda6ffdbcc5f6bfc6aa5d3e4c42d44b038823b..45e05b32f9b66ea0fc0c27c997ebdefecd3fa3c0 100644 (file)
@@ -953,6 +953,7 @@ static const struct x86_cpu_id rapl_ids[] = {
        { X86_VENDOR_INTEL, 6, 0x3a},/* Ivy Bridge */
        { X86_VENDOR_INTEL, 6, 0x3c},/* Haswell */
        { X86_VENDOR_INTEL, 6, 0x3d},/* Broadwell */
+       { X86_VENDOR_INTEL, 6, 0x3f},/* Haswell */
        { X86_VENDOR_INTEL, 6, 0x45},/* Haswell ULT */
        /* TODO: Add more CPU IDs after testing */
        {}
@@ -1166,11 +1167,10 @@ static int rapl_detect_domains(struct rapl_package *rp, int cpu)
 
        for (i = 0; i < RAPL_DOMAIN_MAX; i++) {
                /* use physical package id to read counters */
-               if (!rapl_check_domain(cpu, i))
+               if (!rapl_check_domain(cpu, i)) {
                        rp->domain_map |= 1 << i;
-               else
-                       pr_warn("RAPL domain %s detection failed\n",
-                               rapl_domain_names[i]);
+                       pr_info("Found RAPL domain %s\n", rapl_domain_names[i]);
+               }
        }
        rp->nr_domains = bitmap_weight(&rp->domain_map, RAPL_DOMAIN_MAX);
        if (!rp->nr_domains) {
index 4b66bf09ee550fc391b8b22155dc4610ae649022..d2c35920ff08e7e84e4f1a6be3ce1c15454b2a4b 100644 (file)
@@ -606,6 +606,8 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id)
        unsigned int best = 0;
        struct pwm_lookup *p;
        unsigned int match;
+       unsigned int period;
+       enum pwm_polarity polarity;
 
        /* look up via DT first */
        if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node)
@@ -653,6 +655,8 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id)
                if (match > best) {
                        chip = pwmchip_find_by_name(p->provider);
                        index = p->index;
+                       period = p->period;
+                       polarity = p->polarity;
 
                        if (match != 3)
                                best = match;
@@ -668,8 +672,8 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id)
        if (IS_ERR(pwm))
                return pwm;
 
-       pwm_set_period(pwm, p->period);
-       pwm_set_polarity(pwm, p->polarity);
+       pwm_set_period(pwm, period);
+       pwm_set_polarity(pwm, polarity);
 
 
        return pwm;
index 8f06250a0389cbeffd0a6a0aaf4789ca581c342f..8754c33361e8c70744aa8e468e1579c6876be29e 100644 (file)
@@ -717,12 +717,14 @@ static int s5m_rtc_probe(struct platform_device *pdev)
        info->device_type = s5m87xx->device_type;
        info->wtsr_smpl = s5m87xx->wtsr_smpl;
 
-       info->irq = regmap_irq_get_virq(s5m87xx->irq_data, alarm_irq);
-       if (info->irq <= 0) {
-               ret = -EINVAL;
-               dev_err(&pdev->dev, "Failed to get virtual IRQ %d\n",
+       if (s5m87xx->irq_data) {
+               info->irq = regmap_irq_get_virq(s5m87xx->irq_data, alarm_irq);
+               if (info->irq <= 0) {
+                       ret = -EINVAL;
+                       dev_err(&pdev->dev, "Failed to get virtual IRQ %d\n",
                                alarm_irq);
-               goto err;
+                       goto err;
+               }
        }
 
        platform_set_drvdata(pdev, info);
@@ -744,6 +746,11 @@ static int s5m_rtc_probe(struct platform_device *pdev)
                goto err;
        }
 
+       if (!info->irq) {
+               dev_info(&pdev->dev, "Alarm IRQ not available\n");
+               return 0;
+       }
+
        ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
                                        s5m_rtc_alarm_irq, 0, "rtc-alarm0",
                                        info);
@@ -802,7 +809,7 @@ static int s5m_rtc_resume(struct device *dev)
        struct s5m_rtc_info *info = dev_get_drvdata(dev);
        int ret = 0;
 
-       if (device_may_wakeup(dev))
+       if (info->irq && device_may_wakeup(dev))
                ret = disable_irq_wake(info->irq);
 
        return ret;
@@ -813,7 +820,7 @@ static int s5m_rtc_suspend(struct device *dev)
        struct s5m_rtc_info *info = dev_get_drvdata(dev);
        int ret = 0;
 
-       if (device_may_wakeup(dev))
+       if (info->irq && device_may_wakeup(dev))
                ret = enable_irq_wake(info->irq);
 
        return ret;
index a6d47e5eee9e0add1485533915832107659d2df6..c43aca69fb30dffed727c210b725b46a365440dd 100644 (file)
@@ -1035,12 +1035,26 @@ static int tty3215_write(struct tty_struct * tty,
                         const unsigned char *buf, int count)
 {
        struct raw3215_info *raw;
+       int i, written;
 
        if (!tty)
                return 0;
        raw = (struct raw3215_info *) tty->driver_data;
-       raw3215_write(raw, buf, count);
-       return count;
+       written = count;
+       while (count > 0) {
+               for (i = 0; i < count; i++)
+                       if (buf[i] == '\t' || buf[i] == '\n')
+                               break;
+               raw3215_write(raw, buf, i);
+               count -= i;
+               buf += i;
+               if (count > 0) {
+                       raw3215_putchar(raw, *buf);
+                       count--;
+                       buf++;
+               }
+       }
+       return written;
 }
 
 /*
@@ -1188,7 +1202,7 @@ static int __init tty3215_init(void)
        driver->subtype = SYSTEM_TYPE_TTY;
        driver->init_termios = tty_std_termios;
        driver->init_termios.c_iflag = IGNBRK | IGNPAR;
-       driver->init_termios.c_oflag = ONLCR | XTABS;
+       driver->init_termios.c_oflag = ONLCR;
        driver->init_termios.c_lflag = ISIG;
        driver->flags = TTY_DRIVER_REAL_RAW;
        tty_set_operations(driver, &tty3215_ops);
index 7ed7a59878165bf8ef265e3fae90ee4b10017827..003663288e29b7f60405fa9bf721dcc6dbe19c0c 100644 (file)
@@ -559,7 +559,7 @@ sclp_tty_init(void)
        driver->subtype = SYSTEM_TYPE_TTY;
        driver->init_termios = tty_std_termios;
        driver->init_termios.c_iflag = IGNBRK | IGNPAR;
-       driver->init_termios.c_oflag = ONLCR | XTABS;
+       driver->init_termios.c_oflag = ONLCR;
        driver->init_termios.c_lflag = ISIG | ECHO;
        driver->flags = TTY_DRIVER_REAL_RAW;
        tty_set_operations(driver, &sclp_ops);
index 97ef37b51068369b44d41376e630534d014241a5..e7646ce3d659218ca7fd9762e05cf0d7c4c95a5c 100644 (file)
@@ -889,6 +889,7 @@ extern const struct attribute_group *qeth_generic_attr_groups[];
 extern const struct attribute_group *qeth_osn_attr_groups[];
 extern struct workqueue_struct *qeth_wq;
 
+int qeth_card_hw_is_reachable(struct qeth_card *);
 const char *qeth_get_cardname_short(struct qeth_card *);
 int qeth_realloc_buffer_pool(struct qeth_card *, int);
 int qeth_core_load_discipline(struct qeth_card *, enum qeth_discipline_id);
index c0d6ba8655c742991bc13fe1b2fe2a7a740ea4ac..fd22c811cbe195d2056f6bb5b6339fa33113b8cc 100644 (file)
@@ -73,6 +73,13 @@ static int qeth_init_qdio_out_buf(struct qeth_qdio_out_q *, int);
 struct workqueue_struct *qeth_wq;
 EXPORT_SYMBOL_GPL(qeth_wq);
 
+int qeth_card_hw_is_reachable(struct qeth_card *card)
+{
+       return (card->state == CARD_STATE_SOFTSETUP) ||
+               (card->state == CARD_STATE_UP);
+}
+EXPORT_SYMBOL_GPL(qeth_card_hw_is_reachable);
+
 static void qeth_close_dev_handler(struct work_struct *work)
 {
        struct qeth_card *card;
@@ -5790,6 +5797,7 @@ int qeth_core_ethtool_get_settings(struct net_device *netdev,
        struct qeth_card *card = netdev->ml_priv;
        enum qeth_link_types link_type;
        struct carrier_info carrier_info;
+       int rc;
        u32 speed;
 
        if ((card->info.type == QETH_CARD_TYPE_IQD) || (card->info.guestlan))
@@ -5832,8 +5840,14 @@ int qeth_core_ethtool_get_settings(struct net_device *netdev,
        /* Check if we can obtain more accurate information.     */
        /* If QUERY_CARD_INFO command is not supported or fails, */
        /* just return the heuristics that was filled above.     */
-       if (qeth_query_card_info(card, &carrier_info) != 0)
+       if (!qeth_card_hw_is_reachable(card))
+               return -ENODEV;
+       rc = qeth_query_card_info(card, &carrier_info);
+       if (rc == -EOPNOTSUPP) /* for old hardware, return heuristic */
                return 0;
+       if (rc) /* report error from the hardware operation */
+               return rc;
+       /* on success, fill in the information got from the hardware */
 
        netdev_dbg(netdev,
        "card info: card_type=0x%02x, port_mode=0x%04x, port_speed=0x%08x\n",
index ae1bc04b8653eed571dbbc9a271ec9cdc93205f3..59e3aa538b4da4594456b0965bc0fe42a49379f3 100644 (file)
@@ -5,17 +5,12 @@
 
 #include <linux/slab.h>
 #include <asm/ebcdic.h>
+#include "qeth_core.h"
 #include "qeth_l2.h"
 
 #define QETH_DEVICE_ATTR(_id, _name, _mode, _show, _store) \
 struct device_attribute dev_attr_##_id = __ATTR(_name, _mode, _show, _store)
 
-static int qeth_card_hw_is_reachable(struct qeth_card *card)
-{
-       return (card->state == CARD_STATE_SOFTSETUP) ||
-               (card->state == CARD_STATE_UP);
-}
-
 static ssize_t qeth_bridge_port_role_state_show(struct device *dev,
                                struct device_attribute *attr, char *buf,
                                int show_state)
index f9f3a1224dfa94339e81f5db92c879af049d5d57..ea025e4806b61bb53471e79765bb3c165e31eb8f 100644 (file)
@@ -2097,7 +2097,7 @@ static void iscsi_check_transport_timeouts(unsigned long data)
                                  conn->ping_timeout, conn->recv_timeout,
                                  last_recv, conn->last_ping, jiffies);
                spin_unlock(&session->frwd_lock);
-               iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+               iscsi_conn_failure(conn, ISCSI_ERR_NOP_TIMEDOUT);
                return;
        }
 
index d3a08aea09487e955d51b394b300826183b5c296..7abbf284da1afb7bb1d140a05d48c1f156d37c72 100644 (file)
@@ -526,18 +526,19 @@ static int pm8001_set_nvmd(struct pm8001_hba_info *pm8001_ha)
 {
        struct pm8001_ioctl_payload     *payload;
        DECLARE_COMPLETION_ONSTACK(completion);
-       u8              *ioctlbuffer = NULL;
-       u32             length = 0;
-       u32             ret = 0;
+       u8              *ioctlbuffer;
+       u32             ret;
+       u32             length = 1024 * 5 + sizeof(*payload) - 1;
+
+       if (pm8001_ha->fw_image->size > 4096) {
+               pm8001_ha->fw_status = FAIL_FILE_SIZE;
+               return -EFAULT;
+       }
 
-       length = 1024 * 5 + sizeof(*payload) - 1;
        ioctlbuffer = kzalloc(length, GFP_KERNEL);
-       if (!ioctlbuffer)
+       if (!ioctlbuffer) {
+               pm8001_ha->fw_status = FAIL_OUT_MEMORY;
                return -ENOMEM;
-       if ((pm8001_ha->fw_image->size <= 0) ||
-           (pm8001_ha->fw_image->size > 4096)) {
-               ret = FAIL_FILE_SIZE;
-               goto out;
        }
        payload = (struct pm8001_ioctl_payload *)ioctlbuffer;
        memcpy((u8 *)&payload->func_specific, (u8 *)pm8001_ha->fw_image->data,
@@ -547,6 +548,10 @@ static int pm8001_set_nvmd(struct pm8001_hba_info *pm8001_ha)
        payload->minor_function = 0x1;
        pm8001_ha->nvmd_completion = &completion;
        ret = PM8001_CHIP_DISP->set_nvmd_req(pm8001_ha, payload);
+       if (ret) {
+               pm8001_ha->fw_status = FAIL_OUT_MEMORY;
+               goto out;
+       }
        wait_for_completion(&completion);
 out:
        kfree(ioctlbuffer);
@@ -557,35 +562,31 @@ static int pm8001_update_flash(struct pm8001_hba_info *pm8001_ha)
 {
        struct pm8001_ioctl_payload     *payload;
        DECLARE_COMPLETION_ONSTACK(completion);
-       u8              *ioctlbuffer = NULL;
-       u32             length = 0;
+       u8              *ioctlbuffer;
        struct fw_control_info  *fwControl;
-       u32             loopNumber, loopcount = 0;
-       u32             sizeRead = 0;
        u32             partitionSize, partitionSizeTmp;
-       u32             ret = 0;
-       u32             partitionNumber = 0;
+       u32             loopNumber, loopcount;
        struct pm8001_fw_image_header *image_hdr;
+       u32             sizeRead = 0;
+       u32             ret = 0;
+       u32             length = 1024 * 16 + sizeof(*payload) - 1;
 
-       length = 1024 * 16 + sizeof(*payload) - 1;
+       if (pm8001_ha->fw_image->size < 28) {
+               pm8001_ha->fw_status = FAIL_FILE_SIZE;
+               return -EFAULT;
+       }
        ioctlbuffer = kzalloc(length, GFP_KERNEL);
-       image_hdr = (struct pm8001_fw_image_header *)pm8001_ha->fw_image->data;
-       if (!ioctlbuffer)
+       if (!ioctlbuffer) {
+               pm8001_ha->fw_status = FAIL_OUT_MEMORY;
                return -ENOMEM;
-       if (pm8001_ha->fw_image->size < 28) {
-               ret = FAIL_FILE_SIZE;
-               goto out;
        }
-
+       image_hdr = (struct pm8001_fw_image_header *)pm8001_ha->fw_image->data;
        while (sizeRead < pm8001_ha->fw_image->size) {
                partitionSizeTmp =
                        *(u32 *)((u8 *)&image_hdr->image_length + sizeRead);
                partitionSize = be32_to_cpu(partitionSizeTmp);
-               loopcount = (partitionSize + HEADER_LEN)/IOCTL_BUF_SIZE;
-               if (loopcount % IOCTL_BUF_SIZE)
-                       loopcount++;
-               if (loopcount == 0)
-                       loopcount++;
+               loopcount = DIV_ROUND_UP(partitionSize + HEADER_LEN,
+                                       IOCTL_BUF_SIZE);
                for (loopNumber = 0; loopNumber < loopcount; loopNumber++) {
                        payload = (struct pm8001_ioctl_payload *)ioctlbuffer;
                        payload->length = 1024*16;
@@ -617,18 +618,18 @@ static int pm8001_update_flash(struct pm8001_hba_info *pm8001_ha)
 
                pm8001_ha->nvmd_completion = &completion;
                ret = PM8001_CHIP_DISP->fw_flash_update_req(pm8001_ha, payload);
-               if (ret)
-                       break;
+               if (ret) {
+                       pm8001_ha->fw_status = FAIL_OUT_MEMORY;
+                       goto out;
+               }
                wait_for_completion(&completion);
                if (fwControl->retcode > FLASH_UPDATE_IN_PROGRESS) {
-                       ret = fwControl->retcode;
-                       break;
+                       pm8001_ha->fw_status = fwControl->retcode;
+                       ret = -EFAULT;
+                       goto out;
+               }
                }
        }
-       if (ret)
-               break;
-       partitionNumber++;
-}
 out:
        kfree(ioctlbuffer);
        return ret;
@@ -643,22 +644,29 @@ static ssize_t pm8001_store_update_fw(struct device *cdev,
        char *cmd_ptr, *filename_ptr;
        int res, i;
        int flash_command = FLASH_CMD_NONE;
-       int err = 0;
+       int ret;
+
        if (!capable(CAP_SYS_ADMIN))
                return -EACCES;
 
-       cmd_ptr = kzalloc(count*2, GFP_KERNEL);
+       /* this test protects us from running two flash processes at once,
+        * so we should start with this test */
+       if (pm8001_ha->fw_status == FLASH_IN_PROGRESS)
+               return -EINPROGRESS;
+       pm8001_ha->fw_status = FLASH_IN_PROGRESS;
 
+       cmd_ptr = kzalloc(count*2, GFP_KERNEL);
        if (!cmd_ptr) {
-               err = FAIL_OUT_MEMORY;
-               goto out;
+               pm8001_ha->fw_status = FAIL_OUT_MEMORY;
+               return -ENOMEM;
        }
 
        filename_ptr = cmd_ptr + count;
        res = sscanf(buf, "%s %s", cmd_ptr, filename_ptr);
        if (res != 2) {
-               err = FAIL_PARAMETERS;
-               goto out1;
+               pm8001_ha->fw_status = FAIL_PARAMETERS;
+               ret = -EINVAL;
+               goto out;
        }
 
        for (i = 0; flash_command_table[i].code != FLASH_CMD_NONE; i++) {
@@ -669,50 +677,38 @@ static ssize_t pm8001_store_update_fw(struct device *cdev,
                }
        }
        if (flash_command == FLASH_CMD_NONE) {
-               err = FAIL_PARAMETERS;
-               goto out1;
+               pm8001_ha->fw_status = FAIL_PARAMETERS;
+               ret = -EINVAL;
+               goto out;
        }
 
-       if (pm8001_ha->fw_status == FLASH_IN_PROGRESS) {
-               err = FLASH_IN_PROGRESS;
-               goto out1;
-       }
-       err = request_firmware(&pm8001_ha->fw_image,
+       ret = request_firmware(&pm8001_ha->fw_image,
                               filename_ptr,
                               pm8001_ha->dev);
 
-       if (err) {
+       if (ret) {
                PM8001_FAIL_DBG(pm8001_ha,
-                       pm8001_printk("Failed to load firmware image file %s,"
-                       " error %d\n", filename_ptr, err));
-               err = FAIL_OPEN_BIOS_FILE;
-               goto out1;
+                       pm8001_printk(
+                       "Failed to load firmware image file %s, error %d\n",
+                       filename_ptr, ret));
+               pm8001_ha->fw_status = FAIL_OPEN_BIOS_FILE;
+               goto out;
        }
 
-       switch (flash_command) {
-       case FLASH_CMD_UPDATE:
-               pm8001_ha->fw_status = FLASH_IN_PROGRESS;
-               err = pm8001_update_flash(pm8001_ha);
-               break;
-       case FLASH_CMD_SET_NVMD:
-               pm8001_ha->fw_status = FLASH_IN_PROGRESS;
-               err = pm8001_set_nvmd(pm8001_ha);
-               break;
-       default:
-               pm8001_ha->fw_status = FAIL_PARAMETERS;
-               err = FAIL_PARAMETERS;
-               break;
-       }
+       if (FLASH_CMD_UPDATE == flash_command)
+               ret = pm8001_update_flash(pm8001_ha);
+       else
+               ret = pm8001_set_nvmd(pm8001_ha);
+
        release_firmware(pm8001_ha->fw_image);
-out1:
-       kfree(cmd_ptr);
 out:
-       pm8001_ha->fw_status = err;
+       kfree(cmd_ptr);
 
-       if (!err)
-               return count;
-       else
-               return -err;
+       if (ret)
+               return ret;
+
+       pm8001_ha->fw_status = FLASH_OK;
+       return count;
 }
 
 static ssize_t pm8001_show_update_fw(struct device *cdev,
index 173831016f5f6d3093959d934e0fe598f19b6ffa..dd12c6fe57a67227d51138c8fd7498530078d188 100644 (file)
@@ -4824,7 +4824,7 @@ int pm8001_chip_set_nvmd_req(struct pm8001_hba_info *pm8001_ha,
        rc = pm8001_tag_alloc(pm8001_ha, &tag);
        if (rc) {
                kfree(fw_control_context);
-               return rc;
+               return -EBUSY;
        }
        ccb = &pm8001_ha->ccb_info[tag];
        ccb->fw_control_context = fw_control_context;
@@ -4946,7 +4946,7 @@ pm8001_chip_fw_flash_update_req(struct pm8001_hba_info *pm8001_ha,
        rc = pm8001_tag_alloc(pm8001_ha, &tag);
        if (rc) {
                kfree(fw_control_context);
-               return rc;
+               return -EBUSY;
        }
        ccb = &pm8001_ha->ccb_info[tag];
        ccb->fw_control_context = fw_control_context;
index e49623a897a733d778ca24f8f80a49db16b4aa31..666bf5af06e2d29d26fae7b563a111740c14c9ce 100644 (file)
@@ -748,34 +748,35 @@ static u32 pm8001_setup_msix(struct pm8001_hba_info *pm8001_ha)
                sizeof(pm8001_ha->msix_entries[0]);
        for (i = 0; i < max_entry ; i++)
                pm8001_ha->msix_entries[i].entry = i;
-       rc = pci_enable_msix(pm8001_ha->pdev, pm8001_ha->msix_entries,
+       rc = pci_enable_msix_exact(pm8001_ha->pdev, pm8001_ha->msix_entries,
                number_of_intr);
        pm8001_ha->number_of_intr = number_of_intr;
-       if (!rc) {
-               PM8001_INIT_DBG(pm8001_ha, pm8001_printk(
-                       "pci_enable_msix request ret:%d no of intr %d\n",
-                                       rc, pm8001_ha->number_of_intr));
+       if (rc)
+               return rc;
 
+       PM8001_INIT_DBG(pm8001_ha, pm8001_printk(
+               "pci_enable_msix_exact request ret:%d no of intr %d\n",
+                               rc, pm8001_ha->number_of_intr));
 
-               for (i = 0; i < number_of_intr; i++) {
-                       snprintf(intr_drvname[i], sizeof(intr_drvname[0]),
-                                       DRV_NAME"%d", i);
-                       pm8001_ha->irq_vector[i].irq_id = i;
-                       pm8001_ha->irq_vector[i].drv_inst = pm8001_ha;
+       for (i = 0; i < number_of_intr; i++) {
+               snprintf(intr_drvname[i], sizeof(intr_drvname[0]),
+                               DRV_NAME"%d", i);
+               pm8001_ha->irq_vector[i].irq_id = i;
+               pm8001_ha->irq_vector[i].drv_inst = pm8001_ha;
 
-                       rc = request_irq(pm8001_ha->msix_entries[i].vector,
-                               pm8001_interrupt_handler_msix, flag,
-                               intr_drvname[i], &(pm8001_ha->irq_vector[i]));
-                       if (rc) {
-                               for (j = 0; j < i; j++)
-                                       free_irq(
-                                       pm8001_ha->msix_entries[j].vector,
+               rc = request_irq(pm8001_ha->msix_entries[i].vector,
+                       pm8001_interrupt_handler_msix, flag,
+                       intr_drvname[i], &(pm8001_ha->irq_vector[i]));
+               if (rc) {
+                       for (j = 0; j < i; j++) {
+                               free_irq(pm8001_ha->msix_entries[j].vector,
                                        &(pm8001_ha->irq_vector[i]));
-                               pci_disable_msix(pm8001_ha->pdev);
-                               break;
                        }
+                       pci_disable_msix(pm8001_ha->pdev);
+                       break;
                }
        }
+
        return rc;
 }
 #endif
index 6f12f859b11db787e3b8add134f4d7515cf5ecf4..4180d6d9fe782460d1e09b8d5aa70b9a003c862a 100644 (file)
@@ -334,6 +334,12 @@ void qla4xxx_alloc_fw_dump(struct scsi_qla_host *ha)
        /* Allocate memory for saving the template */
        md_tmp = dma_alloc_coherent(&ha->pdev->dev, ha->fw_dump_tmplt_size,
                                    &md_tmp_dma, GFP_KERNEL);
+       if (!md_tmp) {
+               ql4_printk(KERN_INFO, ha,
+                          "scsi%ld: Failed to allocate DMA memory\n",
+                          ha->host_no);
+               return;
+       }
 
        /* Request template */
        status =  qla4xxx_get_minidump_template(ha, md_tmp_dma);
index fdfae79924ac1df54e6c3b7e66e7afc53fff0736..c291fdff1b338a2ff0ec50930f82298dab279e07 100644 (file)
@@ -1620,8 +1620,8 @@ int qla4xxx_get_chap(struct scsi_qla_host *ha, char *username, char *password,
                goto exit_get_chap;
        }
 
-       strncpy(password, chap_table->secret, QL4_CHAP_MAX_SECRET_LEN);
-       strncpy(username, chap_table->name, QL4_CHAP_MAX_NAME_LEN);
+       strlcpy(password, chap_table->secret, QL4_CHAP_MAX_SECRET_LEN);
+       strlcpy(username, chap_table->name, QL4_CHAP_MAX_NAME_LEN);
        chap_table->cookie = __constant_cpu_to_le16(CHAP_VALID_COOKIE);
 
 exit_get_chap:
@@ -1663,8 +1663,8 @@ int qla4xxx_set_chap(struct scsi_qla_host *ha, char *username, char *password,
        else
                chap_table->flags |= BIT_7; /* local */
        chap_table->secret_len = strlen(password);
-       strncpy(chap_table->secret, password, MAX_CHAP_SECRET_LEN);
-       strncpy(chap_table->name, username, MAX_CHAP_NAME_LEN);
+       strncpy(chap_table->secret, password, MAX_CHAP_SECRET_LEN - 1);
+       strncpy(chap_table->name, username, MAX_CHAP_NAME_LEN - 1);
        chap_table->cookie = __constant_cpu_to_le16(CHAP_VALID_COOKIE);
 
        if (is_qla40XX(ha)) {
@@ -1742,8 +1742,8 @@ int qla4xxx_get_uni_chap_at_index(struct scsi_qla_host *ha, char *username,
                goto exit_unlock_uni_chap;
        }
 
-       strncpy(password, chap_table->secret, MAX_CHAP_SECRET_LEN);
-       strncpy(username, chap_table->name, MAX_CHAP_NAME_LEN);
+       strlcpy(password, chap_table->secret, MAX_CHAP_SECRET_LEN);
+       strlcpy(username, chap_table->name, MAX_CHAP_NAME_LEN);
 
        rval = QLA_SUCCESS;
 
@@ -2295,7 +2295,7 @@ int qla4_8xxx_set_param(struct scsi_qla_host *ha, int param)
        if (param == SET_DRVR_VERSION) {
                mbox_cmd[1] = SET_DRVR_VERSION;
                strncpy((char *)&mbox_cmd[2], QLA4XXX_DRIVER_VERSION,
-                       MAX_DRVR_VER_LEN);
+                       MAX_DRVR_VER_LEN - 1);
        } else {
                ql4_printk(KERN_ERR, ha, "%s: invalid parameter 0x%x\n",
                           __func__, param);
index 9dbdb4be2d8f7258a75043738d819dffcd410146..7c3365864242c9aa7367a030c465f3b4cf5925f9 100644 (file)
@@ -4221,7 +4221,7 @@ qla4_8xxx_enable_msix(struct scsi_qla_host *ha)
        for (i = 0; i < QLA_MSIX_ENTRIES; i++)
                entries[i].entry = qla4_8xxx_msix_entries[i].entry;
 
-       ret = pci_enable_msix(ha->pdev, entries, ARRAY_SIZE(entries));
+       ret = pci_enable_msix_exact(ha->pdev, entries, ARRAY_SIZE(entries));
        if (ret) {
                ql4_printk(KERN_WARNING, ha,
                    "MSI-X: Failed to enable support -- %d/%d\n",
index c5d9564d455ce6ddadd759c884fa13212f09d543..199fcf79a051870c654429c4a9bc92d6baa8b4e5 100644 (file)
@@ -756,9 +756,9 @@ static int qla4xxx_get_chap_list(struct Scsi_Host *shost, uint16_t chap_tbl_idx,
                        continue;
 
                chap_rec->chap_tbl_idx = i;
-               strncpy(chap_rec->username, chap_table->name,
+               strlcpy(chap_rec->username, chap_table->name,
                        ISCSI_CHAP_AUTH_NAME_MAX_LEN);
-               strncpy(chap_rec->password, chap_table->secret,
+               strlcpy(chap_rec->password, chap_table->secret,
                        QL4_CHAP_MAX_SECRET_LEN);
                chap_rec->password_length = chap_table->secret_len;
 
@@ -1050,6 +1050,7 @@ static int qla4xxx_get_host_stats(struct Scsi_Host *shost, char *buf, int len)
        if (!ql_iscsi_stats) {
                ql4_printk(KERN_ERR, ha,
                           "Unable to allocate memory for iscsi stats\n");
+               ret = -ENOMEM;
                goto exit_host_stats;
        }
 
@@ -1058,6 +1059,7 @@ static int qla4xxx_get_host_stats(struct Scsi_Host *shost, char *buf, int len)
        if (ret != QLA_SUCCESS) {
                ql4_printk(KERN_ERR, ha,
                           "Unable to retrieve iscsi stats\n");
+               ret = -EIO;
                goto exit_host_stats;
        }
        host_stats->mactx_frames = le64_to_cpu(ql_iscsi_stats->mac_tx_frames);
@@ -6027,8 +6029,8 @@ static int qla4xxx_get_bidi_chap(struct scsi_qla_host *ha, char *username,
                if (!(chap_table->flags & BIT_6)) /* Not BIDI */
                        continue;
 
-               strncpy(password, chap_table->secret, QL4_CHAP_MAX_SECRET_LEN);
-               strncpy(username, chap_table->name, QL4_CHAP_MAX_NAME_LEN);
+               strlcpy(password, chap_table->secret, QL4_CHAP_MAX_SECRET_LEN);
+               strlcpy(username, chap_table->name, QL4_CHAP_MAX_NAME_LEN);
                ret = 0;
                break;
        }
@@ -6258,8 +6260,8 @@ static void qla4xxx_get_param_ddb(struct ddb_entry *ddb_entry,
 
        tddb->tpgt = sess->tpgt;
        tddb->port = conn->persistent_port;
-       strncpy(tddb->iscsi_name, sess->targetname, ISCSI_NAME_SIZE);
-       strncpy(tddb->ip_addr, conn->persistent_address, DDB_IPADDR_LEN);
+       strlcpy(tddb->iscsi_name, sess->targetname, ISCSI_NAME_SIZE);
+       strlcpy(tddb->ip_addr, conn->persistent_address, DDB_IPADDR_LEN);
 }
 
 static void qla4xxx_convert_param_ddb(struct dev_db_entry *fw_ddb_entry,
@@ -7764,7 +7766,7 @@ static int qla4xxx_sysfs_ddb_logout(struct iscsi_bus_flash_session *fnode_sess,
                goto exit_ddb_logout;
        }
 
-       strncpy(flash_tddb->iscsi_name, fnode_sess->targetname,
+       strlcpy(flash_tddb->iscsi_name, fnode_sess->targetname,
                ISCSI_NAME_SIZE);
 
        if (!strncmp(fnode_sess->portal_type, PORTAL_TYPE_IPV6, 4))
index df3306019a7eeaf2009411ba0328dc7450fc6034..d81f3cc43ff1d3e834fcb6d2dc6460810d167ee8 100644 (file)
@@ -377,6 +377,10 @@ scsi_alloc_host_cmd_pool(struct Scsi_Host *shost)
                pool->slab_flags |= SLAB_CACHE_DMA;
                pool->gfp_mask = __GFP_DMA;
        }
+
+       if (hostt->cmd_size)
+               hostt->cmd_pool = pool;
+
        return pool;
 }
 
@@ -421,8 +425,10 @@ out:
 out_free_slab:
        kmem_cache_destroy(pool->cmd_slab);
 out_free_pool:
-       if (hostt->cmd_size)
+       if (hostt->cmd_size) {
                scsi_free_host_cmd_pool(pool);
+               hostt->cmd_pool = NULL;
+       }
        goto out;
 }
 
@@ -444,8 +450,10 @@ static void scsi_put_host_cmd_pool(struct Scsi_Host *shost)
        if (!--pool->users) {
                kmem_cache_destroy(pool->cmd_slab);
                kmem_cache_destroy(pool->sense_slab);
-               if (hostt->cmd_size)
+               if (hostt->cmd_size) {
                        scsi_free_host_cmd_pool(pool);
+                       hostt->cmd_pool = NULL;
+               }
        }
        mutex_unlock(&host_cmd_pool_mutex);
 }
index 9c44392b748ff88044eeec12eb4dcdb6615e398c..d837dc180522142fa1dcaf5b4e09c141effbfc4a 100644 (file)
@@ -1774,7 +1774,7 @@ static void scsi_request_fn(struct request_queue *q)
        blk_requeue_request(q, req);
        atomic_dec(&sdev->device_busy);
 out_delay:
-       if (atomic_read(&sdev->device_busy) && !scsi_device_blocked(sdev))
+       if (!atomic_read(&sdev->device_busy) && !scsi_device_blocked(sdev))
                blk_delay_queue(q, SCSI_QUEUE_DELAY);
 }
 
@@ -1808,7 +1808,6 @@ static int scsi_mq_prep_fn(struct request *req)
 
        cmd->tag = req->tag;
 
-       req->cmd = req->__cmd;
        cmd->cmnd = req->cmd;
        cmd->prot_op = SCSI_PROT_NORMAL;
 
index b481e62a12cc96945a937972f5c12ebaca488819..67d43e35693df9e9e119bb6a4c2faac56f1bc260 100644 (file)
@@ -3429,7 +3429,7 @@ iscsi_get_host_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)
        char *buf;
 
        if (!transport->get_host_stats)
-               return -EINVAL;
+               return -ENOSYS;
 
        priv = iscsi_if_transport_lookup(transport);
        if (!priv)
@@ -3467,6 +3467,10 @@ iscsi_get_host_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)
                memset(buf, 0, host_stats_size);
 
                err = transport->get_host_stats(shost, buf, host_stats_size);
+               if (err) {
+                       kfree_skb(skbhost_stats);
+                       goto exit_host_stats;
+               }
 
                actual_size = nlmsg_total_size(sizeof(*ev) + host_stats_size);
                skb_trim(skbhost_stats, NLMSG_ALIGN(actual_size));
index 4e76fe863fc4561933e09a646183038bde22d61b..d8dcf36aed11ec5250b8e710cd2796544fac5d23 100644 (file)
@@ -1006,7 +1006,7 @@ static int port_detect \
           sh[j]->irq, dma_name, sh[j]->sg_tablesize, sh[j]->can_queue);
 
    if (sh[j]->max_id > 8 || sh[j]->max_lun > 8)
-      printk("%s: wide SCSI support enabled, max_id %u, max_lun %u.\n",
+      printk("%s: wide SCSI support enabled, max_id %u, max_lun %llu.\n",
              BN(j), sh[j]->max_id, sh[j]->max_lun);
 
    for (i = 0; i <= sh[j]->max_channel; i++)
@@ -1285,7 +1285,7 @@ static int u14_34f_queuecommand_lck(struct scsi_cmnd *SCpnt, void (*done)(struct
    cpp->cpp_index = i;
    SCpnt->host_scribble = (unsigned char *) &cpp->cpp_index;
 
-   if (do_trace) printk("%s: qcomm, mbox %d, target %d.%d:%llu.\n",
+   if (do_trace) printk("%s: qcomm, mbox %d, target %d.%d:%u.\n",
                         BN(j), i, SCpnt->device->channel, SCpnt->device->id,
                         (u8)SCpnt->device->lun);
 
index 788ed9b59b4e3f04c3a485fefe6d31dfdb6b681f..114203f32843216fcddae75fd225ea9b11284417 100644 (file)
@@ -1,8 +1,7 @@
 #
 # Makefile for the SuperH specific drivers.
 #
-obj-$(CONFIG_SUPERH)                   += intc/
-obj-$(CONFIG_ARCH_SHMOBILE_LEGACY)     += intc/
+obj-$(CONFIG_SH_INTC)                  += intc/
 ifneq ($(CONFIG_COMMON_CLK),y)
 obj-$(CONFIG_HAVE_CLK)                 += clk/
 endif
index 60228fae943fb0ac27fcd6ed70c1e0ac2d89f182..6a1b05ddc8c98b087e79580abdf2ff272cbce750 100644 (file)
@@ -1,7 +1,9 @@
 config SH_INTC
-       def_bool y
+       bool
        select IRQ_DOMAIN
 
+if SH_INTC
+
 comment "Interrupt controller options"
 
 config INTC_USERIMASK
@@ -37,3 +39,5 @@ config INTC_MAPPING_DEBUG
          between system IRQs and the per-controller id tables.
 
          If in doubt, say N.
+
+endif
index 40c3d43c9292ddd58e1b3f278a4d8b821a86d6f3..f40b34cdf2fc433ddb9722238cc80004efec52bf 100644 (file)
@@ -945,7 +945,7 @@ static int au1550_spi_remove(struct platform_device *pdev)
        spi_bitbang_stop(&hw->bitbang);
        free_irq(hw->irq, hw);
        iounmap((void __iomem *)hw->regs);
-       release_mem_region(r->start, sizeof(psc_spi_t));
+       release_mem_region(hw->ioarea->start, sizeof(psc_spi_t));
 
        if (hw->usedma) {
                au1550_spi_dma_rxtmp_free(hw);
index 276a3884fb3c1d43c928b0b975b8d7aa67f6be58..48f1d26e6ad9868f9ac8c8e11fb0953e90f707da 100644 (file)
@@ -417,16 +417,16 @@ static int davinci_spi_setup(struct spi_device *spi)
                                                  flags, dev_name(&spi->dev));
                        internal_cs = false;
                }
-       }
 
-       if (retval) {
-               dev_err(&spi->dev, "GPIO %d setup failed (%d)\n",
-                       spi->cs_gpio, retval);
-               return retval;
-       }
+               if (retval) {
+                       dev_err(&spi->dev, "GPIO %d setup failed (%d)\n",
+                               spi->cs_gpio, retval);
+                       return retval;
+               }
 
-       if (internal_cs)
-               set_io_bits(dspi->base + SPIPC0, 1 << spi->chip_select);
+               if (internal_cs)
+                       set_io_bits(dspi->base + SPIPC0, 1 << spi->chip_select);
+       }
 
        if (spi->mode & SPI_READY)
                set_io_bits(dspi->base + SPIPC0, SPIPC0_SPIENA_MASK);
index 3f3dc1226edf19aefad97630e2112287f419cabc..e14960470d8d46a96eef045f612cc4bd23c1a7cb 100644 (file)
@@ -62,6 +62,8 @@ static int spi_pci_probe(struct pci_dev *pdev,
        if (ret)
                return ret;
 
+       dws->regs = pcim_iomap_table(pdev)[pci_bar];
+
        dws->bus_num = 0;
        dws->num_cs = 4;
        dws->irq = pdev->irq;
index 29f33143b795651e773ea7b9d5cc0f80c7cb2575..670f0627f3bfc793092495be55f3d6fd9854dd34 100644 (file)
@@ -271,7 +271,7 @@ static void giveback(struct dw_spi *dws)
                                        transfer_list);
 
        if (!last_transfer->cs_change)
-               spi_chip_sel(dws, dws->cur_msg->spi, 0);
+               spi_chip_sel(dws, msg->spi, 0);
 
        spi_finalize_current_message(dws->master);
 }
index 68441fa448de46323192325154c930afe191f3ab..352eed7463aca0dc23d104178538236f5534257c 100644 (file)
@@ -329,7 +329,8 @@ static void omap2_mcspi_set_fifo(const struct spi_device *spi,
 disable_fifo:
        if (t->rx_buf != NULL)
                chconf &= ~OMAP2_MCSPI_CHCONF_FFER;
-       else
+
+       if (t->tx_buf != NULL)
                chconf &= ~OMAP2_MCSPI_CHCONF_FFET;
 
        mcspi_write_chconf0(spi, chconf);
index fe792106bdc5e65df920368eb495d14fab826841..46f45ca2c69400888de13f390decbf09a30f27d1 100644 (file)
@@ -1074,6 +1074,7 @@ static struct acpi_device_id pxa2xx_spi_acpi_match[] = {
        { "INT3430", 0 },
        { "INT3431", 0 },
        { "80860F0E", 0 },
+       { "8086228E", 0 },
        { },
 };
 MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match);
index c0743604b906c749b62d1fedaaa8f3250b70c0c9..cd0e08b0c9f66c7d99d1421e8fdbf882f62f7e77 100644 (file)
@@ -499,7 +499,7 @@ static void rockchip_spi_config(struct rockchip_spi *rs)
        }
 
        /* div doesn't support odd number */
-       div = rs->max_freq / rs->speed;
+       div = max_t(u32, rs->max_freq / rs->speed, 1);
        div = (div + 1) & 0xfffe;
 
        spi_enable_chip(rs, 0);
@@ -678,7 +678,7 @@ static int rockchip_spi_probe(struct platform_device *pdev)
                rs->dma_tx.addr = (dma_addr_t)(mem->start + ROCKCHIP_SPI_TXDR);
                rs->dma_rx.addr = (dma_addr_t)(mem->start + ROCKCHIP_SPI_RXDR);
                rs->dma_tx.direction = DMA_MEM_TO_DEV;
-               rs->dma_tx.direction = DMA_DEV_TO_MEM;
+               rs->dma_rx.direction = DMA_DEV_TO_MEM;
 
                master->can_dma = rockchip_spi_can_dma;
                master->dma_tx = rs->dma_tx.ch;
index c850dfdfa9e32712136ed7515f1440dbe7906805..ad87a98f8f68f48f4191bac3f2202c45eb26dadf 100644 (file)
@@ -472,25 +472,52 @@ static int rspi_dma_transfer(struct rspi_data *rspi, struct sg_table *tx,
        dma_cookie_t cookie;
        int ret;
 
-       if (tx) {
-               desc_tx = dmaengine_prep_slave_sg(rspi->master->dma_tx,
-                                       tx->sgl, tx->nents, DMA_TO_DEVICE,
-                                       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-               if (!desc_tx)
-                       goto no_dma;
-
-               irq_mask |= SPCR_SPTIE;
-       }
+       /* First prepare and submit the DMA request(s), as this may fail */
        if (rx) {
                desc_rx = dmaengine_prep_slave_sg(rspi->master->dma_rx,
                                        rx->sgl, rx->nents, DMA_FROM_DEVICE,
                                        DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-               if (!desc_rx)
-                       goto no_dma;
+               if (!desc_rx) {
+                       ret = -EAGAIN;
+                       goto no_dma_rx;
+               }
+
+               desc_rx->callback = rspi_dma_complete;
+               desc_rx->callback_param = rspi;
+               cookie = dmaengine_submit(desc_rx);
+               if (dma_submit_error(cookie)) {
+                       ret = cookie;
+                       goto no_dma_rx;
+               }
 
                irq_mask |= SPCR_SPRIE;
        }
 
+       if (tx) {
+               desc_tx = dmaengine_prep_slave_sg(rspi->master->dma_tx,
+                                       tx->sgl, tx->nents, DMA_TO_DEVICE,
+                                       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+               if (!desc_tx) {
+                       ret = -EAGAIN;
+                       goto no_dma_tx;
+               }
+
+               if (rx) {
+                       /* No callback */
+                       desc_tx->callback = NULL;
+               } else {
+                       desc_tx->callback = rspi_dma_complete;
+                       desc_tx->callback_param = rspi;
+               }
+               cookie = dmaengine_submit(desc_tx);
+               if (dma_submit_error(cookie)) {
+                       ret = cookie;
+                       goto no_dma_tx;
+               }
+
+               irq_mask |= SPCR_SPTIE;
+       }
+
        /*
         * DMAC needs SPxIE, but if SPxIE is set, the IRQ routine will be
         * called. So, this driver disables the IRQ while DMA transfer.
@@ -503,34 +530,24 @@ static int rspi_dma_transfer(struct rspi_data *rspi, struct sg_table *tx,
        rspi_enable_irq(rspi, irq_mask);
        rspi->dma_callbacked = 0;
 
-       if (rx) {
-               desc_rx->callback = rspi_dma_complete;
-               desc_rx->callback_param = rspi;
-               cookie = dmaengine_submit(desc_rx);
-               if (dma_submit_error(cookie))
-                       return cookie;
+       /* Now start DMA */
+       if (rx)
                dma_async_issue_pending(rspi->master->dma_rx);
-       }
-       if (tx) {
-               if (rx) {
-                       /* No callback */
-                       desc_tx->callback = NULL;
-               } else {
-                       desc_tx->callback = rspi_dma_complete;
-                       desc_tx->callback_param = rspi;
-               }
-               cookie = dmaengine_submit(desc_tx);
-               if (dma_submit_error(cookie))
-                       return cookie;
+       if (tx)
                dma_async_issue_pending(rspi->master->dma_tx);
-       }
 
        ret = wait_event_interruptible_timeout(rspi->wait,
                                               rspi->dma_callbacked, HZ);
        if (ret > 0 && rspi->dma_callbacked)
                ret = 0;
-       else if (!ret)
+       else if (!ret) {
+               dev_err(&rspi->master->dev, "DMA timeout\n");
                ret = -ETIMEDOUT;
+               if (tx)
+                       dmaengine_terminate_all(rspi->master->dma_tx);
+               if (rx)
+                       dmaengine_terminate_all(rspi->master->dma_rx);
+       }
 
        rspi_disable_irq(rspi, irq_mask);
 
@@ -541,11 +558,16 @@ static int rspi_dma_transfer(struct rspi_data *rspi, struct sg_table *tx,
 
        return ret;
 
-no_dma:
-       pr_warn_once("%s %s: DMA not available, falling back to PIO\n",
-                    dev_driver_string(&rspi->master->dev),
-                    dev_name(&rspi->master->dev));
-       return -EAGAIN;
+no_dma_tx:
+       if (rx)
+               dmaengine_terminate_all(rspi->master->dma_rx);
+no_dma_rx:
+       if (ret == -EAGAIN) {
+               pr_warn_once("%s %s: DMA not available, falling back to PIO\n",
+                            dev_driver_string(&rspi->master->dev),
+                            dev_name(&rspi->master->dev));
+       }
+       return ret;
 }
 
 static void rspi_receive_init(const struct rspi_data *rspi)
index 2a4354dcd6611ffb706105354dc8840513e0c43a..543075b80f166db0a6ec810ab931889d1019a9e4 100644 (file)
@@ -636,48 +636,38 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx,
        dma_cookie_t cookie;
        int ret;
 
-       if (tx) {
-               ier_bits |= IER_TDREQE | IER_TDMAE;
-               dma_sync_single_for_device(p->master->dma_tx->device->dev,
-                                          p->tx_dma_addr, len, DMA_TO_DEVICE);
-               desc_tx = dmaengine_prep_slave_single(p->master->dma_tx,
-                                       p->tx_dma_addr, len, DMA_TO_DEVICE,
-                                       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-               if (!desc_tx)
-                       return -EAGAIN;
-       }
-
+       /* First prepare and submit the DMA request(s), as this may fail */
        if (rx) {
                ier_bits |= IER_RDREQE | IER_RDMAE;
                desc_rx = dmaengine_prep_slave_single(p->master->dma_rx,
                                        p->rx_dma_addr, len, DMA_FROM_DEVICE,
                                        DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-               if (!desc_rx)
-                       return -EAGAIN;
-       }
-
-       /* 1 stage FIFO watermarks for DMA */
-       sh_msiof_write(p, FCTR, FCTR_TFWM_1 | FCTR_RFWM_1);
-
-       /* setup msiof transfer mode registers (32-bit words) */
-       sh_msiof_spi_set_mode_regs(p, tx, rx, 32, len / 4);
-
-       sh_msiof_write(p, IER, ier_bits);
-
-       reinit_completion(&p->done);
+               if (!desc_rx) {
+                       ret = -EAGAIN;
+                       goto no_dma_rx;
+               }
 
-       if (rx) {
                desc_rx->callback = sh_msiof_dma_complete;
                desc_rx->callback_param = p;
                cookie = dmaengine_submit(desc_rx);
                if (dma_submit_error(cookie)) {
                        ret = cookie;
-                       goto stop_ier;
+                       goto no_dma_rx;
                }
-               dma_async_issue_pending(p->master->dma_rx);
        }
 
        if (tx) {
+               ier_bits |= IER_TDREQE | IER_TDMAE;
+               dma_sync_single_for_device(p->master->dma_tx->device->dev,
+                                          p->tx_dma_addr, len, DMA_TO_DEVICE);
+               desc_tx = dmaengine_prep_slave_single(p->master->dma_tx,
+                                       p->tx_dma_addr, len, DMA_TO_DEVICE,
+                                       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+               if (!desc_tx) {
+                       ret = -EAGAIN;
+                       goto no_dma_tx;
+               }
+
                if (rx) {
                        /* No callback */
                        desc_tx->callback = NULL;
@@ -688,15 +678,30 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx,
                cookie = dmaengine_submit(desc_tx);
                if (dma_submit_error(cookie)) {
                        ret = cookie;
-                       goto stop_rx;
+                       goto no_dma_tx;
                }
-               dma_async_issue_pending(p->master->dma_tx);
        }
 
+       /* 1 stage FIFO watermarks for DMA */
+       sh_msiof_write(p, FCTR, FCTR_TFWM_1 | FCTR_RFWM_1);
+
+       /* setup msiof transfer mode registers (32-bit words) */
+       sh_msiof_spi_set_mode_regs(p, tx, rx, 32, len / 4);
+
+       sh_msiof_write(p, IER, ier_bits);
+
+       reinit_completion(&p->done);
+
+       /* Now start DMA */
+       if (rx)
+               dma_async_issue_pending(p->master->dma_rx);
+       if (tx)
+               dma_async_issue_pending(p->master->dma_tx);
+
        ret = sh_msiof_spi_start(p, rx);
        if (ret) {
                dev_err(&p->pdev->dev, "failed to start hardware\n");
-               goto stop_tx;
+               goto stop_dma;
        }
 
        /* wait for tx fifo to be emptied / rx fifo to be filled */
@@ -726,14 +731,14 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx,
 stop_reset:
        sh_msiof_reset_str(p);
        sh_msiof_spi_stop(p, rx);
-stop_tx:
+stop_dma:
        if (tx)
                dmaengine_terminate_all(p->master->dma_tx);
-stop_rx:
+no_dma_tx:
        if (rx)
                dmaengine_terminate_all(p->master->dma_rx);
-stop_ier:
        sh_msiof_write(p, IER, 0);
+no_dma_rx:
        return ret;
 }
 
index e0531baf2782ae78f086db7af5201fcaef4bc92a..ca935df80c88e98b7ae2e8ddbd24cf87c54f55ef 100644 (file)
@@ -848,6 +848,7 @@ out:
 
 /**
  * spi_finalize_current_transfer - report completion of a transfer
+ * @master: the master reporting completion
  *
  * Called by SPI drivers using the core transfer_one_message()
  * implementation to notify it that the current interrupt driven
index 19396dc4ee47f947f569a26308416f99401acb21..bed2fedeb05710f8d17313ee49e5a6e00ce7f471 100644 (file)
@@ -38,6 +38,7 @@ static const struct pci_device_id b43_pci_bridge_tbl[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x432b) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x432c) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4350) },
+       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4351) },
        { 0, },
 };
 MODULE_DEVICE_TABLE(pci, b43_pci_bridge_tbl);
index 2c486ea6236bb99aeb938c9c67bea7d5f39f80e5..35b494f5667f1ca836c01fdcf054e1c4f99d110a 100644 (file)
@@ -28,8 +28,6 @@ source "drivers/staging/et131x/Kconfig"
 
 source "drivers/staging/slicoss/Kconfig"
 
-source "drivers/staging/usbip/Kconfig"
-
 source "drivers/staging/wlan-ng/Kconfig"
 
 source "drivers/staging/comedi/Kconfig"
index 1e1a3a10faf73d8c77fa0621a121e596cfbeddbf..e66a5dbd9b02c35e44ad02bdd0a235181d10a1f1 100644 (file)
@@ -6,7 +6,6 @@ obj-$(CONFIG_STAGING)           += staging.o
 obj-y                          += media/
 obj-$(CONFIG_ET131X)           += et131x/
 obj-$(CONFIG_SLICOSS)          += slicoss/
-obj-$(CONFIG_USBIP_CORE)       += usbip/
 obj-$(CONFIG_PRISM2_USB)       += wlan-ng/
 obj-$(CONFIG_COMEDI)           += comedi/
 obj-$(CONFIG_FB_OLPC_DCON)     += olpc_dcon/
index 9b47e66599a3761ed995db78d57aaf585db6359d..0bf0d24d12d5b8be9f077ba3422a07832ad5e7cb 100644 (file)
@@ -790,7 +790,7 @@ static int __init create_log(char *log_name, int size)
        if (unlikely(ret)) {
                pr_err("failed to register misc device for log '%s'!\n",
                                log->misc.name);
-               goto out_free_log;
+               goto out_free_misc_name;
        }
 
        pr_info("created %luK log '%s'\n",
@@ -798,6 +798,9 @@ static int __init create_log(char *log_name, int size)
 
        return 0;
 
+out_free_misc_name:
+       kfree(log->misc.name);
+
 out_free_log:
        kfree(log);
 
index 8bf1eb48516376e552dbc23c7b6a1969d8488984..831b7c6fe4948074f26604083f350e33d54a5edb 100644 (file)
@@ -1421,22 +1421,16 @@ static int et131x_mii_read(struct et131x_adapter *adapter, u8 reg, u16 *value)
  * @reg: the register to read
  * @value: 16-bit value to write
  */
-static int et131x_mii_write(struct et131x_adapter *adapter, u8 reg, u16 value)
+static int et131x_mii_write(struct et131x_adapter *adapter, u8 addr, u8 reg,
+                           u16 value)
 {
        struct mac_regs __iomem *mac = &adapter->regs->mac;
-       struct phy_device *phydev = adapter->phydev;
        int status = 0;
-       u8 addr;
        u32 delay = 0;
        u32 mii_addr;
        u32 mii_cmd;
        u32 mii_indicator;
 
-       if (!phydev)
-               return -EIO;
-
-       addr = phydev->addr;
-
        /* Save a local copy of the registers we are dealing with so we can
         * set them back
         */
@@ -1631,17 +1625,7 @@ static int et131x_mdio_write(struct mii_bus *bus, int phy_addr,
        struct net_device *netdev = bus->priv;
        struct et131x_adapter *adapter = netdev_priv(netdev);
 
-       return et131x_mii_write(adapter, reg, value);
-}
-
-static int et131x_mdio_reset(struct mii_bus *bus)
-{
-       struct net_device *netdev = bus->priv;
-       struct et131x_adapter *adapter = netdev_priv(netdev);
-
-       et131x_mii_write(adapter, MII_BMCR, BMCR_RESET);
-
-       return 0;
+       return et131x_mii_write(adapter, phy_addr, reg, value);
 }
 
 /*     et1310_phy_power_switch -       PHY power control
@@ -1656,18 +1640,20 @@ static int et131x_mdio_reset(struct mii_bus *bus)
 static void et1310_phy_power_switch(struct et131x_adapter *adapter, bool down)
 {
        u16 data;
+       struct  phy_device *phydev = adapter->phydev;
 
        et131x_mii_read(adapter, MII_BMCR, &data);
        data &= ~BMCR_PDOWN;
        if (down)
                data |= BMCR_PDOWN;
-       et131x_mii_write(adapter, MII_BMCR, data);
+       et131x_mii_write(adapter, phydev->addr, MII_BMCR, data);
 }
 
 /* et131x_xcvr_init - Init the phy if we are setting it into force mode */
 static void et131x_xcvr_init(struct et131x_adapter *adapter)
 {
        u16 lcr2;
+       struct  phy_device *phydev = adapter->phydev;
 
        /* Set the LED behavior such that LED 1 indicates speed (off =
         * 10Mbits, blink = 100Mbits, on = 1000Mbits) and LED 2 indicates
@@ -1688,7 +1674,7 @@ static void et131x_xcvr_init(struct et131x_adapter *adapter)
                else
                        lcr2 |= (LED_VAL_LINKON << LED_TXRX_SHIFT);
 
-               et131x_mii_write(adapter, PHY_LED_2, lcr2);
+               et131x_mii_write(adapter, phydev->addr, PHY_LED_2, lcr2);
        }
 }
 
@@ -3643,14 +3629,14 @@ static void et131x_adjust_link(struct net_device *netdev)
 
                        et131x_mii_read(adapter, PHY_MPHY_CONTROL_REG,
                                         &register18);
-                       et131x_mii_write(adapter, PHY_MPHY_CONTROL_REG,
-                                        register18 | 0x4);
-                       et131x_mii_write(adapter, PHY_INDEX_REG,
+                       et131x_mii_write(adapter, phydev->addr,
+                                        PHY_MPHY_CONTROL_REG, register18 | 0x4);
+                       et131x_mii_write(adapter, phydev->addr, PHY_INDEX_REG,
                                         register18 | 0x8402);
-                       et131x_mii_write(adapter, PHY_DATA_REG,
+                       et131x_mii_write(adapter, phydev->addr, PHY_DATA_REG,
                                         register18 | 511);
-                       et131x_mii_write(adapter, PHY_MPHY_CONTROL_REG,
-                                        register18);
+                       et131x_mii_write(adapter, phydev->addr,
+                                        PHY_MPHY_CONTROL_REG, register18);
                }
 
                et1310_config_flow_control(adapter);
@@ -3662,7 +3648,8 @@ static void et131x_adjust_link(struct net_device *netdev)
                        et131x_mii_read(adapter, PHY_CONFIG, &reg);
                        reg &= ~ET_PHY_CONFIG_TX_FIFO_DEPTH;
                        reg |= ET_PHY_CONFIG_FIFO_DEPTH_32;
-                       et131x_mii_write(adapter, PHY_CONFIG, reg);
+                       et131x_mii_write(adapter, phydev->addr, PHY_CONFIG,
+                                        reg);
                }
 
                et131x_set_rx_dma_timer(adapter);
@@ -3675,14 +3662,14 @@ static void et131x_adjust_link(struct net_device *netdev)
 
                        et131x_mii_read(adapter, PHY_MPHY_CONTROL_REG,
                                         &register18);
-                       et131x_mii_write(adapter, PHY_MPHY_CONTROL_REG,
-                                        register18 | 0x4);
-                       et131x_mii_write(adapter, PHY_INDEX_REG,
-                                        register18 | 0x8402);
-                       et131x_mii_write(adapter, PHY_DATA_REG,
-                                        register18 | 511);
-                       et131x_mii_write(adapter, PHY_MPHY_CONTROL_REG,
-                                        register18);
+                       et131x_mii_write(adapter, phydev->addr,
+                                       PHY_MPHY_CONTROL_REG, register18 | 0x4);
+                       et131x_mii_write(adapter, phydev->addr,
+                                       PHY_INDEX_REG, register18 | 0x8402);
+                       et131x_mii_write(adapter, phydev->addr,
+                                       PHY_DATA_REG, register18 | 511);
+                       et131x_mii_write(adapter, phydev->addr,
+                                       PHY_MPHY_CONTROL_REG, register18);
                }
 
                /* Free the packets being actively sent & stopped */
@@ -4644,10 +4631,6 @@ static int et131x_pci_setup(struct pci_dev *pdev,
        /* Copy address into the net_device struct */
        memcpy(netdev->dev_addr, adapter->addr, ETH_ALEN);
 
-       /* Init variable for counting how long we do not have link status */
-       adapter->boot_coma = 0;
-       et1310_disable_phy_coma(adapter);
-
        rc = -ENOMEM;
 
        /* Setup the mii_bus struct */
@@ -4663,7 +4646,6 @@ static int et131x_pci_setup(struct pci_dev *pdev,
        adapter->mii_bus->priv = netdev;
        adapter->mii_bus->read = et131x_mdio_read;
        adapter->mii_bus->write = et131x_mdio_write;
-       adapter->mii_bus->reset = et131x_mdio_reset;
        adapter->mii_bus->irq = kmalloc_array(PHY_MAX_ADDR, sizeof(int),
                                              GFP_KERNEL);
        if (!adapter->mii_bus->irq)
@@ -4687,6 +4669,10 @@ static int et131x_pci_setup(struct pci_dev *pdev,
        /* Setup et1310 as per the documentation */
        et131x_adapter_setup(adapter);
 
+       /* Init variable for counting how long we do not have link status */
+       adapter->boot_coma = 0;
+       et1310_disable_phy_coma(adapter);
+
        /* We can enable interrupts now
         *
         *  NOTE - Because registration of interrupt handler is done in the
index 65629579bd7d8c11a66c12bd7d43a51ee98ff883..03ab9e046784c0d598b43e26f97fad2ca1aafcdd 100644 (file)
@@ -365,6 +365,7 @@ cfs_wi_sched_create(char *name, struct cfs_cpt_table *cptab,
                return -ENOMEM;
 
        strncpy(sched->ws_name, name, CFS_WS_NAME_LEN);
+       sched->ws_name[CFS_WS_NAME_LEN - 1] = '\0';
        sched->ws_cptab = cptab;
        sched->ws_cpt = cpt;
 
index 8b19f3caa68ff95e4f68691611ca3f1bfcf19159..701c6a77652496260a5aab7e92d93f6ae9e49b34 100644 (file)
@@ -35,7 +35,7 @@
  */
 
 #define DEBUG_SUBSYSTEM S_CLASS
-# include <asm/atomic.h>
+# include <linux/atomic.h>
 
 #include "../include/obd_support.h"
 #include "../include/obd_class.h"
index b8676ac77b0c720040aa2ccd7eae730873ece565..407a318b09dbe2837dc64573792e6f886cc88d62 100644 (file)
@@ -43,9 +43,11 @@ static struct usb_device_id rtw_usb_id_tbl[] = {
        {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x0179)}, /* 8188ETV */
        /*=== Customer ID ===*/
        /****** 8188EUS ********/
+       {USB_DEVICE(0x056e, 0x4008)}, /* Elecom WDC-150SU2M */
        {USB_DEVICE(0x07b8, 0x8179)}, /* Abocom - Abocom */
        {USB_DEVICE(0x2001, 0x330F)}, /* DLink DWA-125 REV D1 */
        {USB_DEVICE(0x2001, 0x3310)}, /* Dlink DWA-123 REV D1 */
+       {USB_DEVICE(0x0df6, 0x0076)}, /* Sitecom N150 v2 */
        {}      /* Terminating entry */
 };
 
index c5fdcb89dacd0b3a11054e98785c2336f94a87d0..2a1502f351f8f1d9ceb8e01ff8add8557a2757cb 100644 (file)
@@ -2128,7 +2128,7 @@ static int on_action_public23a(struct rtw_adapter *padapter,
                                                      IEEE80211_BAND_5GHZ);
 
        if (cfg80211_rx_mgmt(padapter->rtw_wdev, freq, 0, pframe,
-                            skb->len, 0, GFP_ATOMIC))
+                            skb->len, 0))
                return _SUCCESS;
 
        return _FAIL;
index 93dc844a10b35dcebaf05b8c94d53c66715d0e88..8b0ccb5c5fc4fb4d7b095f1fe8d05174c6cc8cf4 100644 (file)
@@ -279,6 +279,7 @@ static int rtw_cfg80211_inform_bss(struct rtw_adapter *padapter,
        }
 
        bss = cfg80211_inform_bss(wiphy, notify_channel,
+                                 CFG80211_BSS_FTYPE_UNKNOWN,
                                  pnetwork->network.MacAddress,
                                  pnetwork->network.tsf,
                                  pnetwork->network.capability,
@@ -2379,7 +2380,7 @@ void rtw_cfg80211_indicate_sta_assoc(struct rtw_adapter *padapter,
                                                      IEEE80211_BAND_5GHZ);
 
        cfg80211_rx_mgmt(padapter->rtw_wdev, freq, 0, pmgmt_frame, frame_len,
-                        0, GFP_ATOMIC);
+                        0);
 #endif /* defined(RTW_USE_CFG80211_STA_EVENT) */
 }
 
@@ -2425,7 +2426,7 @@ void rtw_cfg80211_indicate_sta_disassoc(struct rtw_adapter *padapter,
        frame_len = sizeof(struct ieee80211_hdr_3addr) + 2;
 
        cfg80211_rx_mgmt(padapter->rtw_wdev, freq, 0, (u8 *)&mgmt, frame_len,
-                        0, GFP_ATOMIC);
+                        0);
 #endif /* defined(RTW_USE_CFG80211_STA_EVENT) */
 }
 
diff --git a/drivers/staging/usbip/Kconfig b/drivers/staging/usbip/Kconfig
deleted file mode 100644 (file)
index bd99e9e..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-config USBIP_CORE
-       tristate "USB/IP support"
-       depends on USB && NET
-       ---help---
-         This enables pushing USB packets over IP to allow remote
-         machines direct access to USB devices. It provides the
-         USB/IP core that is required by both drivers.
-
-         For more details, and to get the userspace utility
-         programs, please see <http://usbip.sourceforge.net/>.
-
-         To compile this as a module, choose M here: the module will
-         be called usbip-core.
-
-         If unsure, say N.
-
-config USBIP_VHCI_HCD
-       tristate "VHCI hcd"
-       depends on USBIP_CORE
-       ---help---
-         This enables the USB/IP virtual host controller driver,
-         which is run on the remote machine.
-
-         To compile this driver as a module, choose M here: the
-         module will be called vhci-hcd.
-
-config USBIP_HOST
-       tristate "Host driver"
-       depends on USBIP_CORE
-       ---help---
-         This enables the USB/IP host driver, which is run on the
-         machine that is sharing the USB devices.
-
-         To compile this driver as a module, choose M here: the
-         module will be called usbip-host.
-
-config USBIP_DEBUG
-       bool "Debug messages for USB/IP"
-       depends on USBIP_CORE
-       ---help---
-         This enables the debug messages from the USB/IP drivers.
diff --git a/drivers/staging/usbip/Makefile b/drivers/staging/usbip/Makefile
deleted file mode 100644 (file)
index 9ecd615..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-ccflags-$(CONFIG_USBIP_DEBUG) := -DDEBUG
-
-obj-$(CONFIG_USBIP_CORE) += usbip-core.o
-usbip-core-y := usbip_common.o usbip_event.o
-
-obj-$(CONFIG_USBIP_VHCI_HCD) += vhci-hcd.o
-vhci-hcd-y := vhci_sysfs.o vhci_tx.o vhci_rx.o vhci_hcd.o
-
-obj-$(CONFIG_USBIP_HOST) += usbip-host.o
-usbip-host-y := stub_dev.o stub_main.o stub_rx.o stub_tx.o
diff --git a/drivers/staging/usbip/README b/drivers/staging/usbip/README
deleted file mode 100644 (file)
index 41a2cf2..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-TODO:
-       - more discussion about the protocol
-       - testing
-       - review of the userspace interface
-       - document the protocol
-
-Please send patches for this code to Greg Kroah-Hartman <greg@kroah.com>
diff --git a/drivers/staging/usbip/stub.h b/drivers/staging/usbip/stub.h
deleted file mode 100644 (file)
index 266e2b0..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2003-2008 Takahiro Hirofuchi
- *
- * This 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 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 __USBIP_STUB_H
-#define __USBIP_STUB_H
-
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-#include <linux/usb.h>
-#include <linux/wait.h>
-
-#define STUB_BUSID_OTHER 0
-#define STUB_BUSID_REMOV 1
-#define STUB_BUSID_ADDED 2
-#define STUB_BUSID_ALLOC 3
-
-struct stub_device {
-       struct usb_interface *interface;
-       struct usb_device *udev;
-
-       struct usbip_device ud;
-       __u32 devid;
-
-       /*
-        * stub_priv preserves private data of each urb.
-        * It is allocated as stub_priv_cache and assigned to urb->context.
-        *
-        * stub_priv is always linked to any one of 3 lists;
-        *      priv_init: linked to this until the comletion of a urb.
-        *      priv_tx  : linked to this after the completion of a urb.
-        *      priv_free: linked to this after the sending of the result.
-        *
-        * Any of these list operations should be locked by priv_lock.
-        */
-       spinlock_t priv_lock;
-       struct list_head priv_init;
-       struct list_head priv_tx;
-       struct list_head priv_free;
-
-       /* see comments for unlinking in stub_rx.c */
-       struct list_head unlink_tx;
-       struct list_head unlink_free;
-
-       wait_queue_head_t tx_waitq;
-};
-
-/* private data into urb->priv */
-struct stub_priv {
-       unsigned long seqnum;
-       struct list_head list;
-       struct stub_device *sdev;
-       struct urb *urb;
-
-       int unlinking;
-};
-
-struct stub_unlink {
-       unsigned long seqnum;
-       struct list_head list;
-       __u32 status;
-};
-
-/* same as SYSFS_BUS_ID_SIZE */
-#define BUSID_SIZE 32
-
-struct bus_id_priv {
-       char name[BUSID_SIZE];
-       char status;
-       int interf_count;
-       struct stub_device *sdev;
-       struct usb_device *udev;
-       char shutdown_busid;
-};
-
-/* stub_priv is allocated from stub_priv_cache */
-extern struct kmem_cache *stub_priv_cache;
-
-/* stub_dev.c */
-extern struct usb_device_driver stub_driver;
-
-/* stub_main.c */
-struct bus_id_priv *get_busid_priv(const char *busid);
-int del_match_busid(char *busid);
-void stub_device_cleanup_urbs(struct stub_device *sdev);
-
-/* stub_rx.c */
-int stub_rx_loop(void *data);
-
-/* stub_tx.c */
-void stub_enqueue_ret_unlink(struct stub_device *sdev, __u32 seqnum,
-                            __u32 status);
-void stub_complete(struct urb *urb);
-int stub_tx_loop(void *data);
-
-#endif /* __USBIP_STUB_H */
diff --git a/drivers/staging/usbip/stub_dev.c b/drivers/staging/usbip/stub_dev.c
deleted file mode 100644 (file)
index 51d0c71..0000000
+++ /dev/null
@@ -1,525 +0,0 @@
-/*
- * Copyright (C) 2003-2008 Takahiro Hirofuchi
- *
- * This 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 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/device.h>
-#include <linux/file.h>
-#include <linux/kthread.h>
-#include <linux/module.h>
-
-#include "usbip_common.h"
-#include "stub.h"
-
-/*
- * Define device IDs here if you want to explicitly limit exportable devices.
- * In most cases, wildcard matching will be okay because driver binding can be
- * changed dynamically by a userland program.
- */
-static struct usb_device_id stub_table[] = {
-#if 0
-       /* just an example */
-       { USB_DEVICE(0x05ac, 0x0301) },   /* Mac 1 button mouse */
-       { USB_DEVICE(0x0430, 0x0009) },   /* Plat Home Keyboard */
-       { USB_DEVICE(0x059b, 0x0001) },   /* Iomega USB Zip 100 */
-       { USB_DEVICE(0x04b3, 0x4427) },   /* IBM USB CD-ROM */
-       { USB_DEVICE(0x05a9, 0xa511) },   /* LifeView USB cam */
-       { USB_DEVICE(0x55aa, 0x0201) },   /* Imation card reader */
-       { USB_DEVICE(0x046d, 0x0870) },   /* Qcam Express(QV-30) */
-       { USB_DEVICE(0x04bb, 0x0101) },   /* IO-DATA HD 120GB */
-       { USB_DEVICE(0x04bb, 0x0904) },   /* IO-DATA USB-ET/TX */
-       { USB_DEVICE(0x04bb, 0x0201) },   /* IO-DATA USB-ET/TX */
-       { USB_DEVICE(0x08bb, 0x2702) },   /* ONKYO USB Speaker */
-       { USB_DEVICE(0x046d, 0x08b2) },   /* Logicool Qcam 4000 Pro */
-#endif
-       /* magic for wild card */
-       { .driver_info = 1 },
-       { 0, }                                     /* Terminating entry */
-};
-MODULE_DEVICE_TABLE(usb, stub_table);
-
-/*
- * usbip_status shows the status of usbip-host as long as this driver is bound
- * to the target device.
- */
-static ssize_t usbip_status_show(struct device *dev,
-                                struct device_attribute *attr, char *buf)
-{
-       struct stub_device *sdev = dev_get_drvdata(dev);
-       int status;
-
-       if (!sdev) {
-               dev_err(dev, "sdev is null\n");
-               return -ENODEV;
-       }
-
-       spin_lock_irq(&sdev->ud.lock);
-       status = sdev->ud.status;
-       spin_unlock_irq(&sdev->ud.lock);
-
-       return snprintf(buf, PAGE_SIZE, "%d\n", status);
-}
-static DEVICE_ATTR_RO(usbip_status);
-
-/*
- * usbip_sockfd gets a socket descriptor of an established TCP connection that
- * is used to transfer usbip requests by kernel threads. -1 is a magic number
- * by which usbip connection is finished.
- */
-static ssize_t store_sockfd(struct device *dev, struct device_attribute *attr,
-                           const char *buf, size_t count)
-{
-       struct stub_device *sdev = dev_get_drvdata(dev);
-       int sockfd = 0;
-       struct socket *socket;
-       int rv;
-
-       if (!sdev) {
-               dev_err(dev, "sdev is null\n");
-               return -ENODEV;
-       }
-
-       rv = sscanf(buf, "%d", &sockfd);
-       if (rv != 1)
-               return -EINVAL;
-
-       if (sockfd != -1) {
-               int err;
-
-               dev_info(dev, "stub up\n");
-
-               spin_lock_irq(&sdev->ud.lock);
-
-               if (sdev->ud.status != SDEV_ST_AVAILABLE) {
-                       dev_err(dev, "not ready\n");
-                       goto err;
-               }
-
-               socket = sockfd_lookup(sockfd, &err);
-               if (!socket)
-                       goto err;
-
-               sdev->ud.tcp_socket = socket;
-
-               spin_unlock_irq(&sdev->ud.lock);
-
-               sdev->ud.tcp_rx = kthread_get_run(stub_rx_loop, &sdev->ud,
-                                                 "stub_rx");
-               sdev->ud.tcp_tx = kthread_get_run(stub_tx_loop, &sdev->ud,
-                                                 "stub_tx");
-
-               spin_lock_irq(&sdev->ud.lock);
-               sdev->ud.status = SDEV_ST_USED;
-               spin_unlock_irq(&sdev->ud.lock);
-
-       } else {
-               dev_info(dev, "stub down\n");
-
-               spin_lock_irq(&sdev->ud.lock);
-               if (sdev->ud.status != SDEV_ST_USED)
-                       goto err;
-
-               spin_unlock_irq(&sdev->ud.lock);
-
-               usbip_event_add(&sdev->ud, SDEV_EVENT_DOWN);
-       }
-
-       return count;
-
-err:
-       spin_unlock_irq(&sdev->ud.lock);
-       return -EINVAL;
-}
-static DEVICE_ATTR(usbip_sockfd, S_IWUSR, NULL, store_sockfd);
-
-static int stub_add_files(struct device *dev)
-{
-       int err = 0;
-
-       err = device_create_file(dev, &dev_attr_usbip_status);
-       if (err)
-               goto err_status;
-
-       err = device_create_file(dev, &dev_attr_usbip_sockfd);
-       if (err)
-               goto err_sockfd;
-
-       err = device_create_file(dev, &dev_attr_usbip_debug);
-       if (err)
-               goto err_debug;
-
-       return 0;
-
-err_debug:
-       device_remove_file(dev, &dev_attr_usbip_sockfd);
-err_sockfd:
-       device_remove_file(dev, &dev_attr_usbip_status);
-err_status:
-       return err;
-}
-
-static void stub_remove_files(struct device *dev)
-{
-       device_remove_file(dev, &dev_attr_usbip_status);
-       device_remove_file(dev, &dev_attr_usbip_sockfd);
-       device_remove_file(dev, &dev_attr_usbip_debug);
-}
-
-static void stub_shutdown_connection(struct usbip_device *ud)
-{
-       struct stub_device *sdev = container_of(ud, struct stub_device, ud);
-
-       /*
-        * When removing an exported device, kernel panic sometimes occurred
-        * and then EIP was sk_wait_data of stub_rx thread. Is this because
-        * sk_wait_data returned though stub_rx thread was already finished by
-        * step 1?
-        */
-       if (ud->tcp_socket) {
-               dev_dbg(&sdev->udev->dev, "shutdown tcp_socket %p\n",
-                       ud->tcp_socket);
-               kernel_sock_shutdown(ud->tcp_socket, SHUT_RDWR);
-       }
-
-       /* 1. stop threads */
-       if (ud->tcp_rx) {
-               kthread_stop_put(ud->tcp_rx);
-               ud->tcp_rx = NULL;
-       }
-       if (ud->tcp_tx) {
-               kthread_stop_put(ud->tcp_tx);
-               ud->tcp_tx = NULL;
-       }
-
-       /*
-        * 2. close the socket
-        *
-        * tcp_socket is freed after threads are killed so that usbip_xmit does
-        * not touch NULL socket.
-        */
-       if (ud->tcp_socket) {
-               sockfd_put(ud->tcp_socket);
-               ud->tcp_socket = NULL;
-       }
-
-       /* 3. free used data */
-       stub_device_cleanup_urbs(sdev);
-
-       /* 4. free stub_unlink */
-       {
-               unsigned long flags;
-               struct stub_unlink *unlink, *tmp;
-
-               spin_lock_irqsave(&sdev->priv_lock, flags);
-               list_for_each_entry_safe(unlink, tmp, &sdev->unlink_tx, list) {
-                       list_del(&unlink->list);
-                       kfree(unlink);
-               }
-               list_for_each_entry_safe(unlink, tmp, &sdev->unlink_free,
-                                        list) {
-                       list_del(&unlink->list);
-                       kfree(unlink);
-               }
-               spin_unlock_irqrestore(&sdev->priv_lock, flags);
-       }
-}
-
-static void stub_device_reset(struct usbip_device *ud)
-{
-       struct stub_device *sdev = container_of(ud, struct stub_device, ud);
-       struct usb_device *udev = sdev->udev;
-       int ret;
-
-       dev_dbg(&udev->dev, "device reset");
-
-       ret = usb_lock_device_for_reset(udev, sdev->interface);
-       if (ret < 0) {
-               dev_err(&udev->dev, "lock for reset\n");
-               spin_lock_irq(&ud->lock);
-               ud->status = SDEV_ST_ERROR;
-               spin_unlock_irq(&ud->lock);
-               return;
-       }
-
-       /* try to reset the device */
-       ret = usb_reset_device(udev);
-       usb_unlock_device(udev);
-
-       spin_lock_irq(&ud->lock);
-       if (ret) {
-               dev_err(&udev->dev, "device reset\n");
-               ud->status = SDEV_ST_ERROR;
-       } else {
-               dev_info(&udev->dev, "device reset\n");
-               ud->status = SDEV_ST_AVAILABLE;
-       }
-       spin_unlock_irq(&ud->lock);
-}
-
-static void stub_device_unusable(struct usbip_device *ud)
-{
-       spin_lock_irq(&ud->lock);
-       ud->status = SDEV_ST_ERROR;
-       spin_unlock_irq(&ud->lock);
-}
-
-/**
- * stub_device_alloc - allocate a new stub_device struct
- * @interface: usb_interface of a new device
- *
- * Allocates and initializes a new stub_device struct.
- */
-static struct stub_device *stub_device_alloc(struct usb_device *udev)
-{
-       struct stub_device *sdev;
-       int busnum = udev->bus->busnum;
-       int devnum = udev->devnum;
-
-       dev_dbg(&udev->dev, "allocating stub device");
-
-       /* yes, it's a new device */
-       sdev = kzalloc(sizeof(struct stub_device), GFP_KERNEL);
-       if (!sdev)
-               return NULL;
-
-       sdev->udev = usb_get_dev(udev);
-
-       /*
-        * devid is defined with devnum when this driver is first allocated.
-        * devnum may change later if a device is reset. However, devid never
-        * changes during a usbip connection.
-        */
-       sdev->devid             = (busnum << 16) | devnum;
-       sdev->ud.side           = USBIP_STUB;
-       sdev->ud.status         = SDEV_ST_AVAILABLE;
-       spin_lock_init(&sdev->ud.lock);
-       sdev->ud.tcp_socket     = NULL;
-
-       INIT_LIST_HEAD(&sdev->priv_init);
-       INIT_LIST_HEAD(&sdev->priv_tx);
-       INIT_LIST_HEAD(&sdev->priv_free);
-       INIT_LIST_HEAD(&sdev->unlink_free);
-       INIT_LIST_HEAD(&sdev->unlink_tx);
-       spin_lock_init(&sdev->priv_lock);
-
-       init_waitqueue_head(&sdev->tx_waitq);
-
-       sdev->ud.eh_ops.shutdown = stub_shutdown_connection;
-       sdev->ud.eh_ops.reset    = stub_device_reset;
-       sdev->ud.eh_ops.unusable = stub_device_unusable;
-
-       usbip_start_eh(&sdev->ud);
-
-       dev_dbg(&udev->dev, "register new device\n");
-
-       return sdev;
-}
-
-static void stub_device_free(struct stub_device *sdev)
-{
-       kfree(sdev);
-}
-
-static int stub_probe(struct usb_device *udev)
-{
-       struct stub_device *sdev = NULL;
-       const char *udev_busid = dev_name(&udev->dev);
-       int err = 0;
-       struct bus_id_priv *busid_priv;
-       int rc;
-
-       dev_dbg(&udev->dev, "Enter\n");
-
-       /* check we should claim or not by busid_table */
-       busid_priv = get_busid_priv(udev_busid);
-       if (!busid_priv || (busid_priv->status == STUB_BUSID_REMOV) ||
-           (busid_priv->status == STUB_BUSID_OTHER)) {
-               dev_info(&udev->dev,
-                       "%s is not in match_busid table... skip!\n",
-                       udev_busid);
-
-               /*
-                * Return value should be ENODEV or ENOXIO to continue trying
-                * other matched drivers by the driver core.
-                * See driver_probe_device() in driver/base/dd.c
-                */
-               return -ENODEV;
-       }
-
-       if (udev->descriptor.bDeviceClass == USB_CLASS_HUB) {
-               dev_dbg(&udev->dev, "%s is a usb hub device... skip!\n",
-                        udev_busid);
-               return -ENODEV;
-       }
-
-       if (!strcmp(udev->bus->bus_name, "vhci_hcd")) {
-               dev_dbg(&udev->dev,
-                       "%s is attached on vhci_hcd... skip!\n",
-                       udev_busid);
-
-               return -ENODEV;
-       }
-
-       /* ok, this is my device */
-       sdev = stub_device_alloc(udev);
-       if (!sdev)
-               return -ENOMEM;
-
-       dev_info(&udev->dev,
-               "usbip-host: register new device (bus %u dev %u)\n",
-               udev->bus->busnum, udev->devnum);
-
-       busid_priv->shutdown_busid = 0;
-
-       /* set private data to usb_device */
-       dev_set_drvdata(&udev->dev, sdev);
-       busid_priv->sdev = sdev;
-       busid_priv->udev = udev;
-
-       /*
-        * Claim this hub port.
-        * It doesn't matter what value we pass as owner
-        * (struct dev_state) as long as it is unique.
-        */
-       rc = usb_hub_claim_port(udev->parent, udev->portnum,
-                       (struct usb_dev_state *) udev);
-       if (rc) {
-               dev_dbg(&udev->dev, "unable to claim port\n");
-               return rc;
-       }
-
-       err = stub_add_files(&udev->dev);
-       if (err) {
-               dev_err(&udev->dev, "stub_add_files for %s\n", udev_busid);
-               dev_set_drvdata(&udev->dev, NULL);
-               usb_put_dev(udev);
-               kthread_stop_put(sdev->ud.eh);
-
-               busid_priv->sdev = NULL;
-               stub_device_free(sdev);
-               return err;
-       }
-       busid_priv->status = STUB_BUSID_ALLOC;
-
-       return 0;
-}
-
-static void shutdown_busid(struct bus_id_priv *busid_priv)
-{
-       if (busid_priv->sdev && !busid_priv->shutdown_busid) {
-               busid_priv->shutdown_busid = 1;
-               usbip_event_add(&busid_priv->sdev->ud, SDEV_EVENT_REMOVED);
-
-               /* wait for the stop of the event handler */
-               usbip_stop_eh(&busid_priv->sdev->ud);
-       }
-}
-
-/*
- * called in usb_disconnect() or usb_deregister()
- * but only if actconfig(active configuration) exists
- */
-static void stub_disconnect(struct usb_device *udev)
-{
-       struct stub_device *sdev;
-       const char *udev_busid = dev_name(&udev->dev);
-       struct bus_id_priv *busid_priv;
-       int rc;
-
-       dev_dbg(&udev->dev, "Enter\n");
-
-       busid_priv = get_busid_priv(udev_busid);
-       if (!busid_priv) {
-               BUG();
-               return;
-       }
-
-       sdev = dev_get_drvdata(&udev->dev);
-
-       /* get stub_device */
-       if (!sdev) {
-               dev_err(&udev->dev, "could not get device");
-               return;
-       }
-
-       dev_set_drvdata(&udev->dev, NULL);
-
-       /*
-        * NOTE: rx/tx threads are invoked for each usb_device.
-        */
-       stub_remove_files(&udev->dev);
-
-       /* release port */
-       rc = usb_hub_release_port(udev->parent, udev->portnum,
-                                 (struct usb_dev_state *) udev);
-       if (rc) {
-               dev_dbg(&udev->dev, "unable to release port\n");
-               return;
-       }
-
-       /* If usb reset is called from event handler */
-       if (busid_priv->sdev->ud.eh == current)
-               return;
-
-       /* shutdown the current connection */
-       shutdown_busid(busid_priv);
-
-       usb_put_dev(sdev->udev);
-
-       /* free sdev */
-       busid_priv->sdev = NULL;
-       stub_device_free(sdev);
-
-       if (busid_priv->status == STUB_BUSID_ALLOC) {
-               busid_priv->status = STUB_BUSID_ADDED;
-       } else {
-               busid_priv->status = STUB_BUSID_OTHER;
-               del_match_busid((char *)udev_busid);
-       }
-}
-
-#ifdef CONFIG_PM
-
-/* These functions need usb_port_suspend and usb_port_resume,
- * which reside in drivers/usb/core/usb.h. Skip for now. */
-
-static int stub_suspend(struct usb_device *udev, pm_message_t message)
-{
-       dev_dbg(&udev->dev, "stub_suspend\n");
-
-       return 0;
-}
-
-static int stub_resume(struct usb_device *udev, pm_message_t message)
-{
-       dev_dbg(&udev->dev, "stub_resume\n");
-
-       return 0;
-}
-
-#endif /* CONFIG_PM */
-
-struct usb_device_driver stub_driver = {
-       .name           = "usbip-host",
-       .probe          = stub_probe,
-       .disconnect     = stub_disconnect,
-#ifdef CONFIG_PM
-       .suspend        = stub_suspend,
-       .resume         = stub_resume,
-#endif
-       .supports_autosuspend   =       0,
-};
diff --git a/drivers/staging/usbip/stub_main.c b/drivers/staging/usbip/stub_main.c
deleted file mode 100644 (file)
index 44ab43f..0000000
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * Copyright (C) 2003-2008 Takahiro Hirofuchi
- *
- * This 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 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/string.h>
-#include <linux/module.h>
-#include <linux/device.h>
-
-#include "usbip_common.h"
-#include "stub.h"
-
-#define DRIVER_AUTHOR "Takahiro Hirofuchi"
-#define DRIVER_DESC "USB/IP Host Driver"
-
-struct kmem_cache *stub_priv_cache;
-/*
- * busid_tables defines matching busids that usbip can grab. A user can change
- * dynamically what device is locally used and what device is exported to a
- * remote host.
- */
-#define MAX_BUSID 16
-static struct bus_id_priv busid_table[MAX_BUSID];
-static spinlock_t busid_table_lock;
-
-static void init_busid_table(void)
-{
-       /*
-        * This also sets the bus_table[i].status to
-        * STUB_BUSID_OTHER, which is 0.
-        */
-       memset(busid_table, 0, sizeof(busid_table));
-
-       spin_lock_init(&busid_table_lock);
-}
-
-/*
- * Find the index of the busid by name.
- * Must be called with busid_table_lock held.
- */
-static int get_busid_idx(const char *busid)
-{
-       int i;
-       int idx = -1;
-
-       for (i = 0; i < MAX_BUSID; i++)
-               if (busid_table[i].name[0])
-                       if (!strncmp(busid_table[i].name, busid, BUSID_SIZE)) {
-                               idx = i;
-                               break;
-                       }
-       return idx;
-}
-
-struct bus_id_priv *get_busid_priv(const char *busid)
-{
-       int idx;
-       struct bus_id_priv *bid = NULL;
-
-       spin_lock(&busid_table_lock);
-       idx = get_busid_idx(busid);
-       if (idx >= 0)
-               bid = &(busid_table[idx]);
-       spin_unlock(&busid_table_lock);
-
-       return bid;
-}
-
-static int add_match_busid(char *busid)
-{
-       int i;
-       int ret = -1;
-
-       spin_lock(&busid_table_lock);
-       /* already registered? */
-       if (get_busid_idx(busid) >= 0) {
-               ret = 0;
-               goto out;
-       }
-
-       for (i = 0; i < MAX_BUSID; i++)
-               if (!busid_table[i].name[0]) {
-                       strlcpy(busid_table[i].name, busid, BUSID_SIZE);
-                       if ((busid_table[i].status != STUB_BUSID_ALLOC) &&
-                           (busid_table[i].status != STUB_BUSID_REMOV))
-                               busid_table[i].status = STUB_BUSID_ADDED;
-                       ret = 0;
-                       break;
-               }
-
-out:
-       spin_unlock(&busid_table_lock);
-
-       return ret;
-}
-
-int del_match_busid(char *busid)
-{
-       int idx;
-       int ret = -1;
-
-       spin_lock(&busid_table_lock);
-       idx = get_busid_idx(busid);
-       if (idx < 0)
-               goto out;
-
-       /* found */
-       ret = 0;
-
-       if (busid_table[idx].status == STUB_BUSID_OTHER)
-               memset(busid_table[idx].name, 0, BUSID_SIZE);
-
-       if ((busid_table[idx].status != STUB_BUSID_OTHER) &&
-           (busid_table[idx].status != STUB_BUSID_ADDED))
-               busid_table[idx].status = STUB_BUSID_REMOV;
-
-out:
-       spin_unlock(&busid_table_lock);
-
-       return ret;
-}
-
-static ssize_t show_match_busid(struct device_driver *drv, char *buf)
-{
-       int i;
-       char *out = buf;
-
-       spin_lock(&busid_table_lock);
-       for (i = 0; i < MAX_BUSID; i++)
-               if (busid_table[i].name[0])
-                       out += sprintf(out, "%s ", busid_table[i].name);
-       spin_unlock(&busid_table_lock);
-       out += sprintf(out, "\n");
-
-       return out - buf;
-}
-
-static ssize_t store_match_busid(struct device_driver *dev, const char *buf,
-                                size_t count)
-{
-       int len;
-       char busid[BUSID_SIZE];
-
-       if (count < 5)
-               return -EINVAL;
-
-       /* busid needs to include \0 termination */
-       len = strlcpy(busid, buf + 4, BUSID_SIZE);
-       if (sizeof(busid) <= len)
-               return -EINVAL;
-
-       if (!strncmp(buf, "add ", 4)) {
-               if (add_match_busid(busid) < 0)
-                       return -ENOMEM;
-
-               pr_debug("add busid %s\n", busid);
-               return count;
-       }
-
-       if (!strncmp(buf, "del ", 4)) {
-               if (del_match_busid(busid) < 0)
-                       return -ENODEV;
-
-               pr_debug("del busid %s\n", busid);
-               return count;
-       }
-
-       return -EINVAL;
-}
-static DRIVER_ATTR(match_busid, S_IRUSR | S_IWUSR, show_match_busid,
-                  store_match_busid);
-
-static ssize_t rebind_store(struct device_driver *dev, const char *buf,
-                                size_t count)
-{
-       int ret;
-       int len;
-       struct bus_id_priv *bid;
-
-       /* buf length should be less that BUSID_SIZE */
-       len = strnlen(buf, BUSID_SIZE);
-
-       if (!(len < BUSID_SIZE))
-               return -EINVAL;
-
-       bid = get_busid_priv(buf);
-       if (!bid)
-               return -ENODEV;
-
-       ret = device_attach(&bid->udev->dev);
-       if (ret < 0) {
-               dev_err(&bid->udev->dev, "rebind failed\n");
-               return ret;
-       }
-
-       return count;
-}
-
-static DRIVER_ATTR_WO(rebind);
-
-static struct stub_priv *stub_priv_pop_from_listhead(struct list_head *listhead)
-{
-       struct stub_priv *priv, *tmp;
-
-       list_for_each_entry_safe(priv, tmp, listhead, list) {
-               list_del(&priv->list);
-               return priv;
-       }
-
-       return NULL;
-}
-
-static struct stub_priv *stub_priv_pop(struct stub_device *sdev)
-{
-       unsigned long flags;
-       struct stub_priv *priv;
-
-       spin_lock_irqsave(&sdev->priv_lock, flags);
-
-       priv = stub_priv_pop_from_listhead(&sdev->priv_init);
-       if (priv)
-               goto done;
-
-       priv = stub_priv_pop_from_listhead(&sdev->priv_tx);
-       if (priv)
-               goto done;
-
-       priv = stub_priv_pop_from_listhead(&sdev->priv_free);
-
-done:
-       spin_unlock_irqrestore(&sdev->priv_lock, flags);
-
-       return priv;
-}
-
-void stub_device_cleanup_urbs(struct stub_device *sdev)
-{
-       struct stub_priv *priv;
-       struct urb *urb;
-
-       dev_dbg(&sdev->udev->dev, "free sdev %p\n", sdev);
-
-       while ((priv = stub_priv_pop(sdev))) {
-               urb = priv->urb;
-               dev_dbg(&sdev->udev->dev, "free urb %p\n", urb);
-               usb_kill_urb(urb);
-
-               kmem_cache_free(stub_priv_cache, priv);
-
-               kfree(urb->transfer_buffer);
-               kfree(urb->setup_packet);
-               usb_free_urb(urb);
-       }
-}
-
-static int __init usbip_host_init(void)
-{
-       int ret;
-
-       init_busid_table();
-
-       stub_priv_cache = KMEM_CACHE(stub_priv, SLAB_HWCACHE_ALIGN);
-       if (!stub_priv_cache) {
-               pr_err("kmem_cache_create failed\n");
-               return -ENOMEM;
-       }
-
-       ret = usb_register_device_driver(&stub_driver, THIS_MODULE);
-       if (ret) {
-               pr_err("usb_register failed %d\n", ret);
-               goto err_usb_register;
-       }
-
-       ret = driver_create_file(&stub_driver.drvwrap.driver,
-                                &driver_attr_match_busid);
-       if (ret) {
-               pr_err("driver_create_file failed\n");
-               goto err_create_file;
-       }
-
-       ret = driver_create_file(&stub_driver.drvwrap.driver,
-                                &driver_attr_rebind);
-       if (ret) {
-               pr_err("driver_create_file failed\n");
-               goto err_create_file;
-       }
-
-       pr_info(DRIVER_DESC " v" USBIP_VERSION "\n");
-       return ret;
-
-err_create_file:
-       usb_deregister_device_driver(&stub_driver);
-err_usb_register:
-       kmem_cache_destroy(stub_priv_cache);
-       return ret;
-}
-
-static void __exit usbip_host_exit(void)
-{
-       driver_remove_file(&stub_driver.drvwrap.driver,
-                          &driver_attr_match_busid);
-
-       driver_remove_file(&stub_driver.drvwrap.driver,
-                          &driver_attr_rebind);
-
-       /*
-        * deregister() calls stub_disconnect() for all devices. Device
-        * specific data is cleared in stub_disconnect().
-        */
-       usb_deregister_device_driver(&stub_driver);
-
-       kmem_cache_destroy(stub_priv_cache);
-}
-
-module_init(usbip_host_init);
-module_exit(usbip_host_exit);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-MODULE_VERSION(USBIP_VERSION);
diff --git a/drivers/staging/usbip/stub_rx.c b/drivers/staging/usbip/stub_rx.c
deleted file mode 100644 (file)
index 00e475c..0000000
+++ /dev/null
@@ -1,594 +0,0 @@
-/*
- * Copyright (C) 2003-2008 Takahiro Hirofuchi
- *
- * This 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 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 <asm/byteorder.h>
-#include <linux/kthread.h>
-#include <linux/usb.h>
-#include <linux/usb/hcd.h>
-
-#include "usbip_common.h"
-#include "stub.h"
-
-static int is_clear_halt_cmd(struct urb *urb)
-{
-       struct usb_ctrlrequest *req;
-
-       req = (struct usb_ctrlrequest *) urb->setup_packet;
-
-        return (req->bRequest == USB_REQ_CLEAR_FEATURE) &&
-                (req->bRequestType == USB_RECIP_ENDPOINT) &&
-                (req->wValue == USB_ENDPOINT_HALT);
-}
-
-static int is_set_interface_cmd(struct urb *urb)
-{
-       struct usb_ctrlrequest *req;
-
-       req = (struct usb_ctrlrequest *) urb->setup_packet;
-
-       return (req->bRequest == USB_REQ_SET_INTERFACE) &&
-               (req->bRequestType == USB_RECIP_INTERFACE);
-}
-
-static int is_set_configuration_cmd(struct urb *urb)
-{
-       struct usb_ctrlrequest *req;
-
-       req = (struct usb_ctrlrequest *) urb->setup_packet;
-
-       return (req->bRequest == USB_REQ_SET_CONFIGURATION) &&
-               (req->bRequestType == USB_RECIP_DEVICE);
-}
-
-static int is_reset_device_cmd(struct urb *urb)
-{
-       struct usb_ctrlrequest *req;
-       __u16 value;
-       __u16 index;
-
-       req = (struct usb_ctrlrequest *) urb->setup_packet;
-       value = le16_to_cpu(req->wValue);
-       index = le16_to_cpu(req->wIndex);
-
-       if ((req->bRequest == USB_REQ_SET_FEATURE) &&
-           (req->bRequestType == USB_RT_PORT) &&
-           (value == USB_PORT_FEAT_RESET)) {
-               usbip_dbg_stub_rx("reset_device_cmd, port %u\n", index);
-               return 1;
-       } else
-               return 0;
-}
-
-static int tweak_clear_halt_cmd(struct urb *urb)
-{
-       struct usb_ctrlrequest *req;
-       int target_endp;
-       int target_dir;
-       int target_pipe;
-       int ret;
-
-       req = (struct usb_ctrlrequest *) urb->setup_packet;
-
-       /*
-        * The stalled endpoint is specified in the wIndex value. The endpoint
-        * of the urb is the target of this clear_halt request (i.e., control
-        * endpoint).
-        */
-       target_endp = le16_to_cpu(req->wIndex) & 0x000f;
-
-       /* the stalled endpoint direction is IN or OUT?. USB_DIR_IN is 0x80.  */
-       target_dir = le16_to_cpu(req->wIndex) & 0x0080;
-
-       if (target_dir)
-               target_pipe = usb_rcvctrlpipe(urb->dev, target_endp);
-       else
-               target_pipe = usb_sndctrlpipe(urb->dev, target_endp);
-
-       ret = usb_clear_halt(urb->dev, target_pipe);
-       if (ret < 0)
-               dev_err(&urb->dev->dev,
-                       "usb_clear_halt error: devnum %d endp %d ret %d\n",
-                       urb->dev->devnum, target_endp, ret);
-       else
-               dev_info(&urb->dev->dev,
-                        "usb_clear_halt done: devnum %d endp %d\n",
-                        urb->dev->devnum, target_endp);
-
-       return ret;
-}
-
-static int tweak_set_interface_cmd(struct urb *urb)
-{
-       struct usb_ctrlrequest *req;
-       __u16 alternate;
-       __u16 interface;
-       int ret;
-
-       req = (struct usb_ctrlrequest *) urb->setup_packet;
-       alternate = le16_to_cpu(req->wValue);
-       interface = le16_to_cpu(req->wIndex);
-
-       usbip_dbg_stub_rx("set_interface: inf %u alt %u\n",
-                         interface, alternate);
-
-       ret = usb_set_interface(urb->dev, interface, alternate);
-       if (ret < 0)
-               dev_err(&urb->dev->dev,
-                       "usb_set_interface error: inf %u alt %u ret %d\n",
-                       interface, alternate, ret);
-       else
-               dev_info(&urb->dev->dev,
-                       "usb_set_interface done: inf %u alt %u\n",
-                       interface, alternate);
-
-       return ret;
-}
-
-static int tweak_set_configuration_cmd(struct urb *urb)
-{
-       struct stub_priv *priv = (struct stub_priv *) urb->context;
-       struct stub_device *sdev = priv->sdev;
-       struct usb_ctrlrequest *req;
-       __u16 config;
-       int err;
-
-       req = (struct usb_ctrlrequest *) urb->setup_packet;
-       config = le16_to_cpu(req->wValue);
-
-       err = usb_set_configuration(sdev->udev, config);
-       if (err && err != -ENODEV)
-               dev_err(&sdev->udev->dev, "can't set config #%d, error %d\n",
-                       config, err);
-       return 0;
-}
-
-static int tweak_reset_device_cmd(struct urb *urb)
-{
-       struct stub_priv *priv = (struct stub_priv *) urb->context;
-       struct stub_device *sdev = priv->sdev;
-
-       dev_info(&urb->dev->dev, "usb_queue_reset_device\n");
-
-       /*
-        * With the implementation of pre_reset and post_reset the driver no
-        * longer unbinds. This allows the use of synchronous reset.
-        */
-
-       if (usb_lock_device_for_reset(sdev->udev, sdev->interface) < 0) {
-               dev_err(&urb->dev->dev, "could not obtain lock to reset device\n");
-               return 0;
-       }
-       usb_reset_device(sdev->udev);
-       usb_unlock_device(sdev->udev);
-
-       return 0;
-}
-
-/*
- * clear_halt, set_interface, and set_configuration require special tricks.
- */
-static void tweak_special_requests(struct urb *urb)
-{
-       if (!urb || !urb->setup_packet)
-               return;
-
-       if (usb_pipetype(urb->pipe) != PIPE_CONTROL)
-               return;
-
-       if (is_clear_halt_cmd(urb))
-               /* tweak clear_halt */
-                tweak_clear_halt_cmd(urb);
-
-       else if (is_set_interface_cmd(urb))
-               /* tweak set_interface */
-               tweak_set_interface_cmd(urb);
-
-       else if (is_set_configuration_cmd(urb))
-               /* tweak set_configuration */
-               tweak_set_configuration_cmd(urb);
-
-       else if (is_reset_device_cmd(urb))
-               tweak_reset_device_cmd(urb);
-       else
-               usbip_dbg_stub_rx("no need to tweak\n");
-}
-
-/*
- * stub_recv_unlink() unlinks the URB by a call to usb_unlink_urb().
- * By unlinking the urb asynchronously, stub_rx can continuously
- * process coming urbs.  Even if the urb is unlinked, its completion
- * handler will be called and stub_tx will send a return pdu.
- *
- * See also comments about unlinking strategy in vhci_hcd.c.
- */
-static int stub_recv_cmd_unlink(struct stub_device *sdev,
-                               struct usbip_header *pdu)
-{
-       int ret;
-       unsigned long flags;
-       struct stub_priv *priv;
-
-       spin_lock_irqsave(&sdev->priv_lock, flags);
-
-       list_for_each_entry(priv, &sdev->priv_init, list) {
-               if (priv->seqnum != pdu->u.cmd_unlink.seqnum)
-                       continue;
-
-               dev_info(&priv->urb->dev->dev, "unlink urb %p\n",
-                        priv->urb);
-
-               /*
-                * This matched urb is not completed yet (i.e., be in
-                * flight in usb hcd hardware/driver). Now we are
-                * cancelling it. The unlinking flag means that we are
-                * now not going to return the normal result pdu of a
-                * submission request, but going to return a result pdu
-                * of the unlink request.
-                */
-               priv->unlinking = 1;
-
-               /*
-                * In the case that unlinking flag is on, prev->seqnum
-                * is changed from the seqnum of the cancelling urb to
-                * the seqnum of the unlink request. This will be used
-                * to make the result pdu of the unlink request.
-                */
-               priv->seqnum = pdu->base.seqnum;
-
-               spin_unlock_irqrestore(&sdev->priv_lock, flags);
-
-               /*
-                * usb_unlink_urb() is now out of spinlocking to avoid
-                * spinlock recursion since stub_complete() is
-                * sometimes called in this context but not in the
-                * interrupt context.  If stub_complete() is executed
-                * before we call usb_unlink_urb(), usb_unlink_urb()
-                * will return an error value. In this case, stub_tx
-                * will return the result pdu of this unlink request
-                * though submission is completed and actual unlinking
-                * is not executed. OK?
-                */
-               /* In the above case, urb->status is not -ECONNRESET,
-                * so a driver in a client host will know the failure
-                * of the unlink request ?
-                */
-               ret = usb_unlink_urb(priv->urb);
-               if (ret != -EINPROGRESS)
-                       dev_err(&priv->urb->dev->dev,
-                               "failed to unlink a urb %p, ret %d\n",
-                               priv->urb, ret);
-
-               return 0;
-       }
-
-       usbip_dbg_stub_rx("seqnum %d is not pending\n",
-                         pdu->u.cmd_unlink.seqnum);
-
-       /*
-        * The urb of the unlink target is not found in priv_init queue. It was
-        * already completed and its results is/was going to be sent by a
-        * CMD_RET pdu. In this case, usb_unlink_urb() is not needed. We only
-        * return the completeness of this unlink request to vhci_hcd.
-        */
-       stub_enqueue_ret_unlink(sdev, pdu->base.seqnum, 0);
-
-       spin_unlock_irqrestore(&sdev->priv_lock, flags);
-
-       return 0;
-}
-
-static int valid_request(struct stub_device *sdev, struct usbip_header *pdu)
-{
-       struct usbip_device *ud = &sdev->ud;
-       int valid = 0;
-
-       if (pdu->base.devid == sdev->devid) {
-               spin_lock_irq(&ud->lock);
-               if (ud->status == SDEV_ST_USED) {
-                       /* A request is valid. */
-                       valid = 1;
-               }
-               spin_unlock_irq(&ud->lock);
-       }
-
-       return valid;
-}
-
-static struct stub_priv *stub_priv_alloc(struct stub_device *sdev,
-                                        struct usbip_header *pdu)
-{
-       struct stub_priv *priv;
-       struct usbip_device *ud = &sdev->ud;
-       unsigned long flags;
-
-       spin_lock_irqsave(&sdev->priv_lock, flags);
-
-       priv = kmem_cache_zalloc(stub_priv_cache, GFP_ATOMIC);
-       if (!priv) {
-               dev_err(&sdev->interface->dev, "alloc stub_priv\n");
-               spin_unlock_irqrestore(&sdev->priv_lock, flags);
-               usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC);
-               return NULL;
-       }
-
-       priv->seqnum = pdu->base.seqnum;
-       priv->sdev = sdev;
-
-       /*
-        * After a stub_priv is linked to a list_head,
-        * our error handler can free allocated data.
-        */
-       list_add_tail(&priv->list, &sdev->priv_init);
-
-       spin_unlock_irqrestore(&sdev->priv_lock, flags);
-
-       return priv;
-}
-
-static int get_pipe(struct stub_device *sdev, int epnum, int dir)
-{
-       struct usb_device *udev = sdev->udev;
-       struct usb_host_endpoint *ep;
-       struct usb_endpoint_descriptor *epd = NULL;
-
-       if (dir == USBIP_DIR_IN)
-               ep = udev->ep_in[epnum & 0x7f];
-       else
-               ep = udev->ep_out[epnum & 0x7f];
-       if (!ep) {
-               dev_err(&sdev->interface->dev, "no such endpoint?, %d\n",
-                       epnum);
-               BUG();
-       }
-
-       epd = &ep->desc;
-       if (usb_endpoint_xfer_control(epd)) {
-               if (dir == USBIP_DIR_OUT)
-                       return usb_sndctrlpipe(udev, epnum);
-               else
-                       return usb_rcvctrlpipe(udev, epnum);
-       }
-
-       if (usb_endpoint_xfer_bulk(epd)) {
-               if (dir == USBIP_DIR_OUT)
-                       return usb_sndbulkpipe(udev, epnum);
-               else
-                       return usb_rcvbulkpipe(udev, epnum);
-       }
-
-       if (usb_endpoint_xfer_int(epd)) {
-               if (dir == USBIP_DIR_OUT)
-                       return usb_sndintpipe(udev, epnum);
-               else
-                       return usb_rcvintpipe(udev, epnum);
-       }
-
-       if (usb_endpoint_xfer_isoc(epd)) {
-               if (dir == USBIP_DIR_OUT)
-                       return usb_sndisocpipe(udev, epnum);
-               else
-                       return usb_rcvisocpipe(udev, epnum);
-       }
-
-       /* NOT REACHED */
-       dev_err(&sdev->interface->dev, "get pipe, epnum %d\n", epnum);
-       return 0;
-}
-
-static void masking_bogus_flags(struct urb *urb)
-{
-       int                             xfertype;
-       struct usb_device               *dev;
-       struct usb_host_endpoint        *ep;
-       int                             is_out;
-       unsigned int    allowed;
-
-       if (!urb || urb->hcpriv || !urb->complete)
-               return;
-       dev = urb->dev;
-       if ((!dev) || (dev->state < USB_STATE_UNAUTHENTICATED))
-               return;
-
-       ep = (usb_pipein(urb->pipe) ? dev->ep_in : dev->ep_out)
-               [usb_pipeendpoint(urb->pipe)];
-       if (!ep)
-               return;
-
-       xfertype = usb_endpoint_type(&ep->desc);
-       if (xfertype == USB_ENDPOINT_XFER_CONTROL) {
-               struct usb_ctrlrequest *setup =
-                       (struct usb_ctrlrequest *) urb->setup_packet;
-
-               if (!setup)
-                       return;
-               is_out = !(setup->bRequestType & USB_DIR_IN) ||
-                       !setup->wLength;
-       } else {
-               is_out = usb_endpoint_dir_out(&ep->desc);
-       }
-
-       /* enforce simple/standard policy */
-       allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT |
-                  URB_DIR_MASK | URB_FREE_BUFFER);
-       switch (xfertype) {
-       case USB_ENDPOINT_XFER_BULK:
-               if (is_out)
-                       allowed |= URB_ZERO_PACKET;
-               /* FALLTHROUGH */
-       case USB_ENDPOINT_XFER_CONTROL:
-               allowed |= URB_NO_FSBR; /* only affects UHCI */
-               /* FALLTHROUGH */
-       default:                        /* all non-iso endpoints */
-               if (!is_out)
-                       allowed |= URB_SHORT_NOT_OK;
-               break;
-       case USB_ENDPOINT_XFER_ISOC:
-               allowed |= URB_ISO_ASAP;
-               break;
-       }
-       urb->transfer_flags &= allowed;
-}
-
-static void stub_recv_cmd_submit(struct stub_device *sdev,
-                                struct usbip_header *pdu)
-{
-       int ret;
-       struct stub_priv *priv;
-       struct usbip_device *ud = &sdev->ud;
-       struct usb_device *udev = sdev->udev;
-       int pipe = get_pipe(sdev, pdu->base.ep, pdu->base.direction);
-
-       priv = stub_priv_alloc(sdev, pdu);
-       if (!priv)
-               return;
-
-       /* setup a urb */
-       if (usb_pipeisoc(pipe))
-               priv->urb = usb_alloc_urb(pdu->u.cmd_submit.number_of_packets,
-                                         GFP_KERNEL);
-       else
-               priv->urb = usb_alloc_urb(0, GFP_KERNEL);
-
-       if (!priv->urb) {
-               dev_err(&sdev->interface->dev, "malloc urb\n");
-               usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC);
-               return;
-       }
-
-       /* allocate urb transfer buffer, if needed */
-       if (pdu->u.cmd_submit.transfer_buffer_length > 0) {
-               priv->urb->transfer_buffer =
-                       kzalloc(pdu->u.cmd_submit.transfer_buffer_length,
-                               GFP_KERNEL);
-               if (!priv->urb->transfer_buffer) {
-                       usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC);
-                       return;
-               }
-       }
-
-       /* copy urb setup packet */
-       priv->urb->setup_packet = kmemdup(&pdu->u.cmd_submit.setup, 8,
-                                         GFP_KERNEL);
-       if (!priv->urb->setup_packet) {
-               dev_err(&sdev->interface->dev, "allocate setup_packet\n");
-               usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC);
-               return;
-       }
-
-       /* set other members from the base header of pdu */
-       priv->urb->context                = (void *) priv;
-       priv->urb->dev                    = udev;
-       priv->urb->pipe                   = pipe;
-       priv->urb->complete               = stub_complete;
-
-       usbip_pack_pdu(pdu, priv->urb, USBIP_CMD_SUBMIT, 0);
-
-
-       if (usbip_recv_xbuff(ud, priv->urb) < 0)
-               return;
-
-       if (usbip_recv_iso(ud, priv->urb) < 0)
-               return;
-
-       /* no need to submit an intercepted request, but harmless? */
-       tweak_special_requests(priv->urb);
-
-       masking_bogus_flags(priv->urb);
-       /* urb is now ready to submit */
-       ret = usb_submit_urb(priv->urb, GFP_KERNEL);
-
-       if (ret == 0)
-               usbip_dbg_stub_rx("submit urb ok, seqnum %u\n",
-                                 pdu->base.seqnum);
-       else {
-               dev_err(&sdev->interface->dev, "submit_urb error, %d\n", ret);
-               usbip_dump_header(pdu);
-               usbip_dump_urb(priv->urb);
-
-               /*
-                * Pessimistic.
-                * This connection will be discarded.
-                */
-               usbip_event_add(ud, SDEV_EVENT_ERROR_SUBMIT);
-       }
-
-       usbip_dbg_stub_rx("Leave\n");
-}
-
-/* recv a pdu */
-static void stub_rx_pdu(struct usbip_device *ud)
-{
-       int ret;
-       struct usbip_header pdu;
-       struct stub_device *sdev = container_of(ud, struct stub_device, ud);
-       struct device *dev = &sdev->udev->dev;
-
-       usbip_dbg_stub_rx("Enter\n");
-
-       memset(&pdu, 0, sizeof(pdu));
-
-       /* receive a pdu header */
-       ret = usbip_recv(ud->tcp_socket, &pdu, sizeof(pdu));
-       if (ret != sizeof(pdu)) {
-               dev_err(dev, "recv a header, %d\n", ret);
-               usbip_event_add(ud, SDEV_EVENT_ERROR_TCP);
-               return;
-       }
-
-       usbip_header_correct_endian(&pdu, 0);
-
-       if (usbip_dbg_flag_stub_rx)
-               usbip_dump_header(&pdu);
-
-       if (!valid_request(sdev, &pdu)) {
-               dev_err(dev, "recv invalid request\n");
-               usbip_event_add(ud, SDEV_EVENT_ERROR_TCP);
-               return;
-       }
-
-       switch (pdu.base.command) {
-       case USBIP_CMD_UNLINK:
-               stub_recv_cmd_unlink(sdev, &pdu);
-               break;
-
-       case USBIP_CMD_SUBMIT:
-               stub_recv_cmd_submit(sdev, &pdu);
-               break;
-
-       default:
-               /* NOTREACHED */
-               dev_err(dev, "unknown pdu\n");
-               usbip_event_add(ud, SDEV_EVENT_ERROR_TCP);
-               break;
-       }
-}
-
-int stub_rx_loop(void *data)
-{
-       struct usbip_device *ud = data;
-
-       while (!kthread_should_stop()) {
-               if (usbip_event_happened(ud))
-                       break;
-
-               stub_rx_pdu(ud);
-       }
-
-       return 0;
-}
diff --git a/drivers/staging/usbip/stub_tx.c b/drivers/staging/usbip/stub_tx.c
deleted file mode 100644 (file)
index dbcabc9..0000000
+++ /dev/null
@@ -1,398 +0,0 @@
-/*
- * Copyright (C) 2003-2008 Takahiro Hirofuchi
- *
- * This 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 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/kthread.h>
-#include <linux/socket.h>
-
-#include "usbip_common.h"
-#include "stub.h"
-
-static void stub_free_priv_and_urb(struct stub_priv *priv)
-{
-       struct urb *urb = priv->urb;
-
-       kfree(urb->setup_packet);
-       kfree(urb->transfer_buffer);
-       list_del(&priv->list);
-       kmem_cache_free(stub_priv_cache, priv);
-       usb_free_urb(urb);
-}
-
-/* be in spin_lock_irqsave(&sdev->priv_lock, flags) */
-void stub_enqueue_ret_unlink(struct stub_device *sdev, __u32 seqnum,
-                            __u32 status)
-{
-       struct stub_unlink *unlink;
-
-       unlink = kzalloc(sizeof(struct stub_unlink), GFP_ATOMIC);
-       if (!unlink) {
-               usbip_event_add(&sdev->ud, VDEV_EVENT_ERROR_MALLOC);
-               return;
-       }
-
-       unlink->seqnum = seqnum;
-       unlink->status = status;
-
-       list_add_tail(&unlink->list, &sdev->unlink_tx);
-}
-
-/**
- * stub_complete - completion handler of a usbip urb
- * @urb: pointer to the urb completed
- *
- * When a urb has completed, the USB core driver calls this function mostly in
- * the interrupt context. To return the result of a urb, the completed urb is
- * linked to the pending list of returning.
- *
- */
-void stub_complete(struct urb *urb)
-{
-       struct stub_priv *priv = (struct stub_priv *) urb->context;
-       struct stub_device *sdev = priv->sdev;
-       unsigned long flags;
-
-       usbip_dbg_stub_tx("complete! status %d\n", urb->status);
-
-       switch (urb->status) {
-       case 0:
-               /* OK */
-               break;
-       case -ENOENT:
-               dev_info(&urb->dev->dev,
-                        "stopped by a call to usb_kill_urb() because of cleaning up a virtual connection\n");
-               return;
-       case -ECONNRESET:
-               dev_info(&urb->dev->dev,
-                        "unlinked by a call to usb_unlink_urb()\n");
-               break;
-       case -EPIPE:
-               dev_info(&urb->dev->dev, "endpoint %d is stalled\n",
-                        usb_pipeendpoint(urb->pipe));
-               break;
-       case -ESHUTDOWN:
-               dev_info(&urb->dev->dev, "device removed?\n");
-               break;
-       default:
-               dev_info(&urb->dev->dev,
-                        "urb completion with non-zero status %d\n",
-                        urb->status);
-               break;
-       }
-
-       /* link a urb to the queue of tx. */
-       spin_lock_irqsave(&sdev->priv_lock, flags);
-       if (priv->unlinking) {
-               stub_enqueue_ret_unlink(sdev, priv->seqnum, urb->status);
-               stub_free_priv_and_urb(priv);
-       } else {
-               list_move_tail(&priv->list, &sdev->priv_tx);
-       }
-       spin_unlock_irqrestore(&sdev->priv_lock, flags);
-
-       /* wake up tx_thread */
-       wake_up(&sdev->tx_waitq);
-}
-
-static inline void setup_base_pdu(struct usbip_header_basic *base,
-                                 __u32 command, __u32 seqnum)
-{
-       base->command   = command;
-       base->seqnum    = seqnum;
-       base->devid     = 0;
-       base->ep        = 0;
-       base->direction = 0;
-}
-
-static void setup_ret_submit_pdu(struct usbip_header *rpdu, struct urb *urb)
-{
-       struct stub_priv *priv = (struct stub_priv *) urb->context;
-
-       setup_base_pdu(&rpdu->base, USBIP_RET_SUBMIT, priv->seqnum);
-       usbip_pack_pdu(rpdu, urb, USBIP_RET_SUBMIT, 1);
-}
-
-static void setup_ret_unlink_pdu(struct usbip_header *rpdu,
-                                struct stub_unlink *unlink)
-{
-       setup_base_pdu(&rpdu->base, USBIP_RET_UNLINK, unlink->seqnum);
-       rpdu->u.ret_unlink.status = unlink->status;
-}
-
-static struct stub_priv *dequeue_from_priv_tx(struct stub_device *sdev)
-{
-       unsigned long flags;
-       struct stub_priv *priv, *tmp;
-
-       spin_lock_irqsave(&sdev->priv_lock, flags);
-
-       list_for_each_entry_safe(priv, tmp, &sdev->priv_tx, list) {
-               list_move_tail(&priv->list, &sdev->priv_free);
-               spin_unlock_irqrestore(&sdev->priv_lock, flags);
-               return priv;
-       }
-
-       spin_unlock_irqrestore(&sdev->priv_lock, flags);
-
-       return NULL;
-}
-
-static int stub_send_ret_submit(struct stub_device *sdev)
-{
-       unsigned long flags;
-       struct stub_priv *priv, *tmp;
-
-       struct msghdr msg;
-       size_t txsize;
-
-       size_t total_size = 0;
-
-       while ((priv = dequeue_from_priv_tx(sdev)) != NULL) {
-               int ret;
-               struct urb *urb = priv->urb;
-               struct usbip_header pdu_header;
-               struct usbip_iso_packet_descriptor *iso_buffer = NULL;
-               struct kvec *iov = NULL;
-               int iovnum = 0;
-
-               txsize = 0;
-               memset(&pdu_header, 0, sizeof(pdu_header));
-               memset(&msg, 0, sizeof(msg));
-
-               if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
-                       iovnum = 2 + urb->number_of_packets;
-               else
-                       iovnum = 2;
-
-               iov = kcalloc(iovnum, sizeof(struct kvec), GFP_KERNEL);
-
-               if (!iov) {
-                       usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_MALLOC);
-                       return -1;
-               }
-
-               iovnum = 0;
-
-               /* 1. setup usbip_header */
-               setup_ret_submit_pdu(&pdu_header, urb);
-               usbip_dbg_stub_tx("setup txdata seqnum: %d urb: %p\n",
-                                 pdu_header.base.seqnum, urb);
-               usbip_header_correct_endian(&pdu_header, 1);
-
-               iov[iovnum].iov_base = &pdu_header;
-               iov[iovnum].iov_len  = sizeof(pdu_header);
-               iovnum++;
-               txsize += sizeof(pdu_header);
-
-               /* 2. setup transfer buffer */
-               if (usb_pipein(urb->pipe) &&
-                   usb_pipetype(urb->pipe) != PIPE_ISOCHRONOUS &&
-                   urb->actual_length > 0) {
-                       iov[iovnum].iov_base = urb->transfer_buffer;
-                       iov[iovnum].iov_len  = urb->actual_length;
-                       iovnum++;
-                       txsize += urb->actual_length;
-               } else if (usb_pipein(urb->pipe) &&
-                          usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
-                       /*
-                        * For isochronous packets: actual length is the sum of
-                        * the actual length of the individual, packets, but as
-                        * the packet offsets are not changed there will be
-                        * padding between the packets. To optimally use the
-                        * bandwidth the padding is not transmitted.
-                        */
-
-                       int i;
-
-                       for (i = 0; i < urb->number_of_packets; i++) {
-                               iov[iovnum].iov_base = urb->transfer_buffer +
-                                       urb->iso_frame_desc[i].offset;
-                               iov[iovnum].iov_len =
-                                       urb->iso_frame_desc[i].actual_length;
-                               iovnum++;
-                               txsize += urb->iso_frame_desc[i].actual_length;
-                       }
-
-                       if (txsize != sizeof(pdu_header) + urb->actual_length) {
-                               dev_err(&sdev->interface->dev,
-                                       "actual length of urb %d does not match iso packet sizes %zu\n",
-                                       urb->actual_length,
-                                       txsize-sizeof(pdu_header));
-                               kfree(iov);
-                               usbip_event_add(&sdev->ud,
-                                               SDEV_EVENT_ERROR_TCP);
-                          return -1;
-                       }
-               }
-
-               /* 3. setup iso_packet_descriptor */
-               if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
-                       ssize_t len = 0;
-
-                       iso_buffer = usbip_alloc_iso_desc_pdu(urb, &len);
-                       if (!iso_buffer) {
-                               usbip_event_add(&sdev->ud,
-                                               SDEV_EVENT_ERROR_MALLOC);
-                               kfree(iov);
-                               return -1;
-                       }
-
-                       iov[iovnum].iov_base = iso_buffer;
-                       iov[iovnum].iov_len  = len;
-                       txsize += len;
-                       iovnum++;
-               }
-
-               ret = kernel_sendmsg(sdev->ud.tcp_socket, &msg,
-                                               iov,  iovnum, txsize);
-               if (ret != txsize) {
-                       dev_err(&sdev->interface->dev,
-                               "sendmsg failed!, retval %d for %zd\n",
-                               ret, txsize);
-                       kfree(iov);
-                       kfree(iso_buffer);
-                       usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_TCP);
-                       return -1;
-               }
-
-               kfree(iov);
-               kfree(iso_buffer);
-
-               total_size += txsize;
-       }
-
-       spin_lock_irqsave(&sdev->priv_lock, flags);
-       list_for_each_entry_safe(priv, tmp, &sdev->priv_free, list) {
-               stub_free_priv_and_urb(priv);
-       }
-       spin_unlock_irqrestore(&sdev->priv_lock, flags);
-
-       return total_size;
-}
-
-static struct stub_unlink *dequeue_from_unlink_tx(struct stub_device *sdev)
-{
-       unsigned long flags;
-       struct stub_unlink *unlink, *tmp;
-
-       spin_lock_irqsave(&sdev->priv_lock, flags);
-
-       list_for_each_entry_safe(unlink, tmp, &sdev->unlink_tx, list) {
-               list_move_tail(&unlink->list, &sdev->unlink_free);
-               spin_unlock_irqrestore(&sdev->priv_lock, flags);
-               return unlink;
-       }
-
-       spin_unlock_irqrestore(&sdev->priv_lock, flags);
-
-       return NULL;
-}
-
-static int stub_send_ret_unlink(struct stub_device *sdev)
-{
-       unsigned long flags;
-       struct stub_unlink *unlink, *tmp;
-
-       struct msghdr msg;
-       struct kvec iov[1];
-       size_t txsize;
-
-       size_t total_size = 0;
-
-       while ((unlink = dequeue_from_unlink_tx(sdev)) != NULL) {
-               int ret;
-               struct usbip_header pdu_header;
-
-               txsize = 0;
-               memset(&pdu_header, 0, sizeof(pdu_header));
-               memset(&msg, 0, sizeof(msg));
-               memset(&iov, 0, sizeof(iov));
-
-               usbip_dbg_stub_tx("setup ret unlink %lu\n", unlink->seqnum);
-
-               /* 1. setup usbip_header */
-               setup_ret_unlink_pdu(&pdu_header, unlink);
-               usbip_header_correct_endian(&pdu_header, 1);
-
-               iov[0].iov_base = &pdu_header;
-               iov[0].iov_len  = sizeof(pdu_header);
-               txsize += sizeof(pdu_header);
-
-               ret = kernel_sendmsg(sdev->ud.tcp_socket, &msg, iov,
-                                    1, txsize);
-               if (ret != txsize) {
-                       dev_err(&sdev->interface->dev,
-                               "sendmsg failed!, retval %d for %zd\n",
-                               ret, txsize);
-                       usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_TCP);
-                       return -1;
-               }
-
-               usbip_dbg_stub_tx("send txdata\n");
-               total_size += txsize;
-       }
-
-       spin_lock_irqsave(&sdev->priv_lock, flags);
-
-       list_for_each_entry_safe(unlink, tmp, &sdev->unlink_free, list) {
-               list_del(&unlink->list);
-               kfree(unlink);
-       }
-
-       spin_unlock_irqrestore(&sdev->priv_lock, flags);
-
-       return total_size;
-}
-
-int stub_tx_loop(void *data)
-{
-       struct usbip_device *ud = data;
-       struct stub_device *sdev = container_of(ud, struct stub_device, ud);
-
-       while (!kthread_should_stop()) {
-               if (usbip_event_happened(ud))
-                       break;
-
-               /*
-                * send_ret_submit comes earlier than send_ret_unlink.  stub_rx
-                * looks at only priv_init queue. If the completion of a URB is
-                * earlier than the receive of CMD_UNLINK, priv is moved to
-                * priv_tx queue and stub_rx does not find the target priv. In
-                * this case, vhci_rx receives the result of the submit request
-                * and then receives the result of the unlink request. The
-                * result of the submit is given back to the usbcore as the
-                * completion of the unlink request. The request of the
-                * unlink is ignored. This is ok because a driver who calls
-                * usb_unlink_urb() understands the unlink was too late by
-                * getting the status of the given-backed URB which has the
-                * status of usb_submit_urb().
-                */
-               if (stub_send_ret_submit(sdev) < 0)
-                       break;
-
-               if (stub_send_ret_unlink(sdev) < 0)
-                       break;
-
-               wait_event_interruptible(sdev->tx_waitq,
-                                        (!list_empty(&sdev->priv_tx) ||
-                                         !list_empty(&sdev->unlink_tx) ||
-                                         kthread_should_stop()));
-       }
-
-       return 0;
-}
diff --git a/drivers/staging/usbip/uapi/usbip.h b/drivers/staging/usbip/uapi/usbip.h
deleted file mode 100644 (file)
index fa5db30..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- *     usbip.h
- *
- *     USBIP uapi defines and function prototypes etc.
-*/
-
-#ifndef _UAPI_LINUX_USBIP_H
-#define _UAPI_LINUX_USBIP_H
-
-/* usbip device status - exported in usbip device sysfs status */
-enum usbip_device_status {
-       /* sdev is available. */
-       SDEV_ST_AVAILABLE = 0x01,
-       /* sdev is now used. */
-       SDEV_ST_USED,
-       /* sdev is unusable because of a fatal error. */
-       SDEV_ST_ERROR,
-
-       /* vdev does not connect a remote device. */
-       VDEV_ST_NULL,
-       /* vdev is used, but the USB address is not assigned yet */
-       VDEV_ST_NOTASSIGNED,
-       VDEV_ST_USED,
-       VDEV_ST_ERROR
-};
-#endif /* _UAPI_LINUX_USBIP_H */
diff --git a/drivers/staging/usbip/usbip_common.c b/drivers/staging/usbip/usbip_common.c
deleted file mode 100644 (file)
index facaaf0..0000000
+++ /dev/null
@@ -1,776 +0,0 @@
-/*
- * Copyright (C) 2003-2008 Takahiro Hirofuchi
- *
- * This 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 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 <asm/byteorder.h>
-#include <linux/file.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/stat.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <net/sock.h>
-
-#include "usbip_common.h"
-
-#define DRIVER_AUTHOR "Takahiro Hirofuchi <hirofuchi@users.sourceforge.net>"
-#define DRIVER_DESC "USB/IP Core"
-
-#ifdef CONFIG_USBIP_DEBUG
-unsigned long usbip_debug_flag = 0xffffffff;
-#else
-unsigned long usbip_debug_flag;
-#endif
-EXPORT_SYMBOL_GPL(usbip_debug_flag);
-module_param(usbip_debug_flag, ulong, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(usbip_debug_flag, "debug flags (defined in usbip_common.h)");
-
-/* FIXME */
-struct device_attribute dev_attr_usbip_debug;
-EXPORT_SYMBOL_GPL(dev_attr_usbip_debug);
-
-static ssize_t usbip_debug_show(struct device *dev,
-                               struct device_attribute *attr, char *buf)
-{
-       return sprintf(buf, "%lx\n", usbip_debug_flag);
-}
-
-static ssize_t usbip_debug_store(struct device *dev,
-                                struct device_attribute *attr, const char *buf,
-                                size_t count)
-{
-       if (sscanf(buf, "%lx", &usbip_debug_flag) != 1)
-               return -EINVAL;
-       return count;
-}
-DEVICE_ATTR_RW(usbip_debug);
-
-static void usbip_dump_buffer(char *buff, int bufflen)
-{
-       print_hex_dump(KERN_DEBUG, "usbip-core", DUMP_PREFIX_OFFSET, 16, 4,
-                      buff, bufflen, false);
-}
-
-static void usbip_dump_pipe(unsigned int p)
-{
-       unsigned char type = usb_pipetype(p);
-       unsigned char ep   = usb_pipeendpoint(p);
-       unsigned char dev  = usb_pipedevice(p);
-       unsigned char dir  = usb_pipein(p);
-
-       pr_debug("dev(%d) ep(%d) [%s] ", dev, ep, dir ? "IN" : "OUT");
-
-       switch (type) {
-       case PIPE_ISOCHRONOUS:
-               pr_debug("ISO\n");
-               break;
-       case PIPE_INTERRUPT:
-               pr_debug("INT\n");
-               break;
-       case PIPE_CONTROL:
-               pr_debug("CTRL\n");
-               break;
-       case PIPE_BULK:
-               pr_debug("BULK\n");
-               break;
-       default:
-               pr_debug("ERR\n");
-               break;
-       }
-}
-
-static void usbip_dump_usb_device(struct usb_device *udev)
-{
-       struct device *dev = &udev->dev;
-       int i;
-
-       dev_dbg(dev, "       devnum(%d) devpath(%s) usb speed(%s)",
-               udev->devnum, udev->devpath, usb_speed_string(udev->speed));
-
-       pr_debug("tt %p, ttport %d\n", udev->tt, udev->ttport);
-
-       dev_dbg(dev, "                    ");
-       for (i = 0; i < 16; i++)
-               pr_debug(" %2u", i);
-       pr_debug("\n");
-
-       dev_dbg(dev, "       toggle0(IN) :");
-       for (i = 0; i < 16; i++)
-               pr_debug(" %2u", (udev->toggle[0] & (1 << i)) ? 1 : 0);
-       pr_debug("\n");
-
-       dev_dbg(dev, "       toggle1(OUT):");
-       for (i = 0; i < 16; i++)
-               pr_debug(" %2u", (udev->toggle[1] & (1 << i)) ? 1 : 0);
-       pr_debug("\n");
-
-       dev_dbg(dev, "       epmaxp_in   :");
-       for (i = 0; i < 16; i++) {
-               if (udev->ep_in[i])
-                       pr_debug(" %2u",
-                           le16_to_cpu(udev->ep_in[i]->desc.wMaxPacketSize));
-       }
-       pr_debug("\n");
-
-       dev_dbg(dev, "       epmaxp_out  :");
-       for (i = 0; i < 16; i++) {
-               if (udev->ep_out[i])
-                       pr_debug(" %2u",
-                           le16_to_cpu(udev->ep_out[i]->desc.wMaxPacketSize));
-       }
-       pr_debug("\n");
-
-       dev_dbg(dev, "parent %p, bus %p\n", udev->parent, udev->bus);
-
-       dev_dbg(dev,
-               "descriptor %p, config %p, actconfig %p, rawdescriptors %p\n",
-               &udev->descriptor, udev->config,
-               udev->actconfig, udev->rawdescriptors);
-
-       dev_dbg(dev, "have_langid %d, string_langid %d\n",
-               udev->have_langid, udev->string_langid);
-
-       dev_dbg(dev, "maxchild %d\n", udev->maxchild);
-}
-
-static void usbip_dump_request_type(__u8 rt)
-{
-       switch (rt & USB_RECIP_MASK) {
-       case USB_RECIP_DEVICE:
-               pr_debug("DEVICE");
-               break;
-       case USB_RECIP_INTERFACE:
-               pr_debug("INTERF");
-               break;
-       case USB_RECIP_ENDPOINT:
-               pr_debug("ENDPOI");
-               break;
-       case USB_RECIP_OTHER:
-               pr_debug("OTHER ");
-               break;
-       default:
-               pr_debug("------");
-               break;
-       }
-}
-
-static void usbip_dump_usb_ctrlrequest(struct usb_ctrlrequest *cmd)
-{
-       if (!cmd) {
-               pr_debug("       : null pointer\n");
-               return;
-       }
-
-       pr_debug("       ");
-       pr_debug("bRequestType(%02X) bRequest(%02X) wValue(%04X) wIndex(%04X) wLength(%04X) ",
-                cmd->bRequestType, cmd->bRequest,
-                cmd->wValue, cmd->wIndex, cmd->wLength);
-       pr_debug("\n       ");
-
-       if ((cmd->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
-               pr_debug("STANDARD ");
-               switch (cmd->bRequest) {
-               case USB_REQ_GET_STATUS:
-                       pr_debug("GET_STATUS\n");
-                       break;
-               case USB_REQ_CLEAR_FEATURE:
-                       pr_debug("CLEAR_FEAT\n");
-                       break;
-               case USB_REQ_SET_FEATURE:
-                       pr_debug("SET_FEAT\n");
-                       break;
-               case USB_REQ_SET_ADDRESS:
-                       pr_debug("SET_ADDRRS\n");
-                       break;
-               case USB_REQ_GET_DESCRIPTOR:
-                       pr_debug("GET_DESCRI\n");
-                       break;
-               case USB_REQ_SET_DESCRIPTOR:
-                       pr_debug("SET_DESCRI\n");
-                       break;
-               case USB_REQ_GET_CONFIGURATION:
-                       pr_debug("GET_CONFIG\n");
-                       break;
-               case USB_REQ_SET_CONFIGURATION:
-                       pr_debug("SET_CONFIG\n");
-                       break;
-               case USB_REQ_GET_INTERFACE:
-                       pr_debug("GET_INTERF\n");
-                       break;
-               case USB_REQ_SET_INTERFACE:
-                       pr_debug("SET_INTERF\n");
-                       break;
-               case USB_REQ_SYNCH_FRAME:
-                       pr_debug("SYNC_FRAME\n");
-                       break;
-               default:
-                       pr_debug("REQ(%02X)\n", cmd->bRequest);
-                       break;
-               }
-               usbip_dump_request_type(cmd->bRequestType);
-       } else if ((cmd->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS) {
-               pr_debug("CLASS\n");
-       } else if ((cmd->bRequestType & USB_TYPE_MASK) == USB_TYPE_VENDOR) {
-               pr_debug("VENDOR\n");
-       } else if ((cmd->bRequestType & USB_TYPE_MASK) == USB_TYPE_RESERVED) {
-               pr_debug("RESERVED\n");
-       }
-}
-
-void usbip_dump_urb(struct urb *urb)
-{
-       struct device *dev;
-
-       if (!urb) {
-               pr_debug("urb: null pointer!!\n");
-               return;
-       }
-
-       if (!urb->dev) {
-               pr_debug("urb->dev: null pointer!!\n");
-               return;
-       }
-
-       dev = &urb->dev->dev;
-
-       dev_dbg(dev, "   urb                   :%p\n", urb);
-       dev_dbg(dev, "   dev                   :%p\n", urb->dev);
-
-       usbip_dump_usb_device(urb->dev);
-
-       dev_dbg(dev, "   pipe                  :%08x ", urb->pipe);
-
-       usbip_dump_pipe(urb->pipe);
-
-       dev_dbg(dev, "   status                :%d\n", urb->status);
-       dev_dbg(dev, "   transfer_flags        :%08X\n", urb->transfer_flags);
-       dev_dbg(dev, "   transfer_buffer       :%p\n", urb->transfer_buffer);
-       dev_dbg(dev, "   transfer_buffer_length:%d\n",
-                                               urb->transfer_buffer_length);
-       dev_dbg(dev, "   actual_length         :%d\n", urb->actual_length);
-       dev_dbg(dev, "   setup_packet          :%p\n", urb->setup_packet);
-
-       if (urb->setup_packet && usb_pipetype(urb->pipe) == PIPE_CONTROL)
-               usbip_dump_usb_ctrlrequest(
-                       (struct usb_ctrlrequest *)urb->setup_packet);
-
-       dev_dbg(dev, "   start_frame           :%d\n", urb->start_frame);
-       dev_dbg(dev, "   number_of_packets     :%d\n", urb->number_of_packets);
-       dev_dbg(dev, "   interval              :%d\n", urb->interval);
-       dev_dbg(dev, "   error_count           :%d\n", urb->error_count);
-       dev_dbg(dev, "   context               :%p\n", urb->context);
-       dev_dbg(dev, "   complete              :%p\n", urb->complete);
-}
-EXPORT_SYMBOL_GPL(usbip_dump_urb);
-
-void usbip_dump_header(struct usbip_header *pdu)
-{
-       pr_debug("BASE: cmd %u seq %u devid %u dir %u ep %u\n",
-                pdu->base.command,
-                pdu->base.seqnum,
-                pdu->base.devid,
-                pdu->base.direction,
-                pdu->base.ep);
-
-       switch (pdu->base.command) {
-       case USBIP_CMD_SUBMIT:
-               pr_debug("USBIP_CMD_SUBMIT: x_flags %u x_len %u sf %u #p %d iv %d\n",
-                        pdu->u.cmd_submit.transfer_flags,
-                        pdu->u.cmd_submit.transfer_buffer_length,
-                        pdu->u.cmd_submit.start_frame,
-                        pdu->u.cmd_submit.number_of_packets,
-                        pdu->u.cmd_submit.interval);
-               break;
-       case USBIP_CMD_UNLINK:
-               pr_debug("USBIP_CMD_UNLINK: seq %u\n",
-                        pdu->u.cmd_unlink.seqnum);
-               break;
-       case USBIP_RET_SUBMIT:
-               pr_debug("USBIP_RET_SUBMIT: st %d al %u sf %d #p %d ec %d\n",
-                        pdu->u.ret_submit.status,
-                        pdu->u.ret_submit.actual_length,
-                        pdu->u.ret_submit.start_frame,
-                        pdu->u.ret_submit.number_of_packets,
-                        pdu->u.ret_submit.error_count);
-               break;
-       case USBIP_RET_UNLINK:
-               pr_debug("USBIP_RET_UNLINK: status %d\n",
-                        pdu->u.ret_unlink.status);
-               break;
-       default:
-               /* NOT REACHED */
-               pr_err("unknown command\n");
-               break;
-       }
-}
-EXPORT_SYMBOL_GPL(usbip_dump_header);
-
-/* Receive data over TCP/IP. */
-int usbip_recv(struct socket *sock, void *buf, int size)
-{
-       int result;
-       struct msghdr msg;
-       struct kvec iov;
-       int total = 0;
-
-       /* for blocks of if (usbip_dbg_flag_xmit) */
-       char *bp = buf;
-       int osize = size;
-
-       usbip_dbg_xmit("enter\n");
-
-       if (!sock || !buf || !size) {
-               pr_err("invalid arg, sock %p buff %p size %d\n", sock, buf,
-                      size);
-               return -EINVAL;
-       }
-
-       do {
-               sock->sk->sk_allocation = GFP_NOIO;
-               iov.iov_base    = buf;
-               iov.iov_len     = size;
-               msg.msg_name    = NULL;
-               msg.msg_namelen = 0;
-               msg.msg_control = NULL;
-               msg.msg_controllen = 0;
-               msg.msg_flags      = MSG_NOSIGNAL;
-
-               result = kernel_recvmsg(sock, &msg, &iov, 1, size, MSG_WAITALL);
-               if (result <= 0) {
-                       pr_debug("receive sock %p buf %p size %u ret %d total %d\n",
-                                sock, buf, size, result, total);
-                       goto err;
-               }
-
-               size -= result;
-               buf += result;
-               total += result;
-       } while (size > 0);
-
-       if (usbip_dbg_flag_xmit) {
-               if (!in_interrupt())
-                       pr_debug("%-10s:", current->comm);
-               else
-                       pr_debug("interrupt  :");
-
-               pr_debug("receiving....\n");
-               usbip_dump_buffer(bp, osize);
-               pr_debug("received, osize %d ret %d size %d total %d\n",
-                        osize, result, size, total);
-       }
-
-       return total;
-
-err:
-       return result;
-}
-EXPORT_SYMBOL_GPL(usbip_recv);
-
-/* there may be more cases to tweak the flags. */
-static unsigned int tweak_transfer_flags(unsigned int flags)
-{
-       flags &= ~URB_NO_TRANSFER_DMA_MAP;
-       return flags;
-}
-
-static void usbip_pack_cmd_submit(struct usbip_header *pdu, struct urb *urb,
-                                 int pack)
-{
-       struct usbip_header_cmd_submit *spdu = &pdu->u.cmd_submit;
-
-       /*
-        * Some members are not still implemented in usbip. I hope this issue
-        * will be discussed when usbip is ported to other operating systems.
-        */
-       if (pack) {
-               spdu->transfer_flags =
-                       tweak_transfer_flags(urb->transfer_flags);
-               spdu->transfer_buffer_length    = urb->transfer_buffer_length;
-               spdu->start_frame               = urb->start_frame;
-               spdu->number_of_packets         = urb->number_of_packets;
-               spdu->interval                  = urb->interval;
-       } else  {
-               urb->transfer_flags         = spdu->transfer_flags;
-               urb->transfer_buffer_length = spdu->transfer_buffer_length;
-               urb->start_frame            = spdu->start_frame;
-               urb->number_of_packets      = spdu->number_of_packets;
-               urb->interval               = spdu->interval;
-       }
-}
-
-static void usbip_pack_ret_submit(struct usbip_header *pdu, struct urb *urb,
-                                 int pack)
-{
-       struct usbip_header_ret_submit *rpdu = &pdu->u.ret_submit;
-
-       if (pack) {
-               rpdu->status            = urb->status;
-               rpdu->actual_length     = urb->actual_length;
-               rpdu->start_frame       = urb->start_frame;
-               rpdu->number_of_packets = urb->number_of_packets;
-               rpdu->error_count       = urb->error_count;
-       } else {
-               urb->status             = rpdu->status;
-               urb->actual_length      = rpdu->actual_length;
-               urb->start_frame        = rpdu->start_frame;
-               urb->number_of_packets = rpdu->number_of_packets;
-               urb->error_count        = rpdu->error_count;
-       }
-}
-
-void usbip_pack_pdu(struct usbip_header *pdu, struct urb *urb, int cmd,
-                   int pack)
-{
-       switch (cmd) {
-       case USBIP_CMD_SUBMIT:
-               usbip_pack_cmd_submit(pdu, urb, pack);
-               break;
-       case USBIP_RET_SUBMIT:
-               usbip_pack_ret_submit(pdu, urb, pack);
-               break;
-       default:
-               /* NOT REACHED */
-               pr_err("unknown command\n");
-               break;
-       }
-}
-EXPORT_SYMBOL_GPL(usbip_pack_pdu);
-
-static void correct_endian_basic(struct usbip_header_basic *base, int send)
-{
-       if (send) {
-               base->command   = cpu_to_be32(base->command);
-               base->seqnum    = cpu_to_be32(base->seqnum);
-               base->devid     = cpu_to_be32(base->devid);
-               base->direction = cpu_to_be32(base->direction);
-               base->ep        = cpu_to_be32(base->ep);
-       } else {
-               base->command   = be32_to_cpu(base->command);
-               base->seqnum    = be32_to_cpu(base->seqnum);
-               base->devid     = be32_to_cpu(base->devid);
-               base->direction = be32_to_cpu(base->direction);
-               base->ep        = be32_to_cpu(base->ep);
-       }
-}
-
-static void correct_endian_cmd_submit(struct usbip_header_cmd_submit *pdu,
-                                     int send)
-{
-       if (send) {
-               pdu->transfer_flags = cpu_to_be32(pdu->transfer_flags);
-
-               cpu_to_be32s(&pdu->transfer_buffer_length);
-               cpu_to_be32s(&pdu->start_frame);
-               cpu_to_be32s(&pdu->number_of_packets);
-               cpu_to_be32s(&pdu->interval);
-       } else {
-               pdu->transfer_flags = be32_to_cpu(pdu->transfer_flags);
-
-               be32_to_cpus(&pdu->transfer_buffer_length);
-               be32_to_cpus(&pdu->start_frame);
-               be32_to_cpus(&pdu->number_of_packets);
-               be32_to_cpus(&pdu->interval);
-       }
-}
-
-static void correct_endian_ret_submit(struct usbip_header_ret_submit *pdu,
-                                     int send)
-{
-       if (send) {
-               cpu_to_be32s(&pdu->status);
-               cpu_to_be32s(&pdu->actual_length);
-               cpu_to_be32s(&pdu->start_frame);
-               cpu_to_be32s(&pdu->number_of_packets);
-               cpu_to_be32s(&pdu->error_count);
-       } else {
-               be32_to_cpus(&pdu->status);
-               be32_to_cpus(&pdu->actual_length);
-               be32_to_cpus(&pdu->start_frame);
-               be32_to_cpus(&pdu->number_of_packets);
-               be32_to_cpus(&pdu->error_count);
-       }
-}
-
-static void correct_endian_cmd_unlink(struct usbip_header_cmd_unlink *pdu,
-                                     int send)
-{
-       if (send)
-               pdu->seqnum = cpu_to_be32(pdu->seqnum);
-       else
-               pdu->seqnum = be32_to_cpu(pdu->seqnum);
-}
-
-static void correct_endian_ret_unlink(struct usbip_header_ret_unlink *pdu,
-                                     int send)
-{
-       if (send)
-               cpu_to_be32s(&pdu->status);
-       else
-               be32_to_cpus(&pdu->status);
-}
-
-void usbip_header_correct_endian(struct usbip_header *pdu, int send)
-{
-       __u32 cmd = 0;
-
-       if (send)
-               cmd = pdu->base.command;
-
-       correct_endian_basic(&pdu->base, send);
-
-       if (!send)
-               cmd = pdu->base.command;
-
-       switch (cmd) {
-       case USBIP_CMD_SUBMIT:
-               correct_endian_cmd_submit(&pdu->u.cmd_submit, send);
-               break;
-       case USBIP_RET_SUBMIT:
-               correct_endian_ret_submit(&pdu->u.ret_submit, send);
-               break;
-       case USBIP_CMD_UNLINK:
-               correct_endian_cmd_unlink(&pdu->u.cmd_unlink, send);
-               break;
-       case USBIP_RET_UNLINK:
-               correct_endian_ret_unlink(&pdu->u.ret_unlink, send);
-               break;
-       default:
-               /* NOT REACHED */
-               pr_err("unknown command\n");
-               break;
-       }
-}
-EXPORT_SYMBOL_GPL(usbip_header_correct_endian);
-
-static void usbip_iso_packet_correct_endian(
-               struct usbip_iso_packet_descriptor *iso, int send)
-{
-       /* does not need all members. but copy all simply. */
-       if (send) {
-               iso->offset     = cpu_to_be32(iso->offset);
-               iso->length     = cpu_to_be32(iso->length);
-               iso->status     = cpu_to_be32(iso->status);
-               iso->actual_length = cpu_to_be32(iso->actual_length);
-       } else {
-               iso->offset     = be32_to_cpu(iso->offset);
-               iso->length     = be32_to_cpu(iso->length);
-               iso->status     = be32_to_cpu(iso->status);
-               iso->actual_length = be32_to_cpu(iso->actual_length);
-       }
-}
-
-static void usbip_pack_iso(struct usbip_iso_packet_descriptor *iso,
-                          struct usb_iso_packet_descriptor *uiso, int pack)
-{
-       if (pack) {
-               iso->offset             = uiso->offset;
-               iso->length             = uiso->length;
-               iso->status             = uiso->status;
-               iso->actual_length      = uiso->actual_length;
-       } else {
-               uiso->offset            = iso->offset;
-               uiso->length            = iso->length;
-               uiso->status            = iso->status;
-               uiso->actual_length     = iso->actual_length;
-       }
-}
-
-/* must free buffer */
-struct usbip_iso_packet_descriptor*
-usbip_alloc_iso_desc_pdu(struct urb *urb, ssize_t *bufflen)
-{
-       struct usbip_iso_packet_descriptor *iso;
-       int np = urb->number_of_packets;
-       ssize_t size = np * sizeof(*iso);
-       int i;
-
-       iso = kzalloc(size, GFP_KERNEL);
-       if (!iso)
-               return NULL;
-
-       for (i = 0; i < np; i++) {
-               usbip_pack_iso(&iso[i], &urb->iso_frame_desc[i], 1);
-               usbip_iso_packet_correct_endian(&iso[i], 1);
-       }
-
-       *bufflen = size;
-
-       return iso;
-}
-EXPORT_SYMBOL_GPL(usbip_alloc_iso_desc_pdu);
-
-/* some members of urb must be substituted before. */
-int usbip_recv_iso(struct usbip_device *ud, struct urb *urb)
-{
-       void *buff;
-       struct usbip_iso_packet_descriptor *iso;
-       int np = urb->number_of_packets;
-       int size = np * sizeof(*iso);
-       int i;
-       int ret;
-       int total_length = 0;
-
-       if (!usb_pipeisoc(urb->pipe))
-               return 0;
-
-       /* my Bluetooth dongle gets ISO URBs which are np = 0 */
-       if (np == 0)
-               return 0;
-
-       buff = kzalloc(size, GFP_KERNEL);
-       if (!buff)
-               return -ENOMEM;
-
-       ret = usbip_recv(ud->tcp_socket, buff, size);
-       if (ret != size) {
-               dev_err(&urb->dev->dev, "recv iso_frame_descriptor, %d\n",
-                       ret);
-               kfree(buff);
-
-               if (ud->side == USBIP_STUB)
-                       usbip_event_add(ud, SDEV_EVENT_ERROR_TCP);
-               else
-                       usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
-
-               return -EPIPE;
-       }
-
-       iso = (struct usbip_iso_packet_descriptor *) buff;
-       for (i = 0; i < np; i++) {
-               usbip_iso_packet_correct_endian(&iso[i], 0);
-               usbip_pack_iso(&iso[i], &urb->iso_frame_desc[i], 0);
-               total_length += urb->iso_frame_desc[i].actual_length;
-       }
-
-       kfree(buff);
-
-       if (total_length != urb->actual_length) {
-               dev_err(&urb->dev->dev,
-                       "total length of iso packets %d not equal to actual length of buffer %d\n",
-                       total_length, urb->actual_length);
-
-               if (ud->side == USBIP_STUB)
-                       usbip_event_add(ud, SDEV_EVENT_ERROR_TCP);
-               else
-                       usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
-
-               return -EPIPE;
-       }
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(usbip_recv_iso);
-
-/*
- * This functions restores the padding which was removed for optimizing
- * the bandwidth during transfer over tcp/ip
- *
- * buffer and iso packets need to be stored and be in propeper endian in urb
- * before calling this function
- */
-void usbip_pad_iso(struct usbip_device *ud, struct urb *urb)
-{
-       int np = urb->number_of_packets;
-       int i;
-       int actualoffset = urb->actual_length;
-
-       if (!usb_pipeisoc(urb->pipe))
-               return;
-
-       /* if no packets or length of data is 0, then nothing to unpack */
-       if (np == 0 || urb->actual_length == 0)
-               return;
-
-       /*
-        * if actual_length is transfer_buffer_length then no padding is
-        * present.
-        */
-       if (urb->actual_length == urb->transfer_buffer_length)
-               return;
-
-       /*
-        * loop over all packets from last to first (to prevent overwritting
-        * memory when padding) and move them into the proper place
-        */
-       for (i = np-1; i > 0; i--) {
-               actualoffset -= urb->iso_frame_desc[i].actual_length;
-               memmove(urb->transfer_buffer + urb->iso_frame_desc[i].offset,
-                       urb->transfer_buffer + actualoffset,
-                       urb->iso_frame_desc[i].actual_length);
-       }
-}
-EXPORT_SYMBOL_GPL(usbip_pad_iso);
-
-/* some members of urb must be substituted before. */
-int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb)
-{
-       int ret;
-       int size;
-
-       if (ud->side == USBIP_STUB) {
-               /* the direction of urb must be OUT. */
-               if (usb_pipein(urb->pipe))
-                       return 0;
-
-               size = urb->transfer_buffer_length;
-       } else {
-               /* the direction of urb must be IN. */
-               if (usb_pipeout(urb->pipe))
-                       return 0;
-
-               size = urb->actual_length;
-       }
-
-       /* no need to recv xbuff */
-       if (!(size > 0))
-               return 0;
-
-       ret = usbip_recv(ud->tcp_socket, urb->transfer_buffer, size);
-       if (ret != size) {
-               dev_err(&urb->dev->dev, "recv xbuf, %d\n", ret);
-               if (ud->side == USBIP_STUB) {
-                       usbip_event_add(ud, SDEV_EVENT_ERROR_TCP);
-               } else {
-                       usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
-                       return -EPIPE;
-               }
-       }
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(usbip_recv_xbuff);
-
-static int __init usbip_core_init(void)
-{
-       pr_info(DRIVER_DESC " v" USBIP_VERSION "\n");
-       return 0;
-}
-
-static void __exit usbip_core_exit(void)
-{
-       return;
-}
-
-module_init(usbip_core_init);
-module_exit(usbip_core_exit);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-MODULE_VERSION(USBIP_VERSION);
diff --git a/drivers/staging/usbip/usbip_common.h b/drivers/staging/usbip/usbip_common.h
deleted file mode 100644 (file)
index 4da3866..0000000
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * Copyright (C) 2003-2008 Takahiro Hirofuchi
- *
- * This 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 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 __USBIP_COMMON_H
-#define __USBIP_COMMON_H
-
-#include <linux/compiler.h>
-#include <linux/device.h>
-#include <linux/interrupt.h>
-#include <linux/net.h>
-#include <linux/printk.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-#include <linux/usb.h>
-#include <linux/wait.h>
-#include "uapi/usbip.h"
-
-#define USBIP_VERSION "1.0.0"
-
-#undef pr_fmt
-
-#ifdef DEBUG
-#define pr_fmt(fmt)     KBUILD_MODNAME ": %s:%d: " fmt, __func__, __LINE__
-#else
-#define pr_fmt(fmt)     KBUILD_MODNAME ": " fmt
-#endif
-
-enum {
-       usbip_debug_xmit        = (1 << 0),
-       usbip_debug_sysfs       = (1 << 1),
-       usbip_debug_urb         = (1 << 2),
-       usbip_debug_eh          = (1 << 3),
-
-       usbip_debug_stub_cmp    = (1 << 8),
-       usbip_debug_stub_dev    = (1 << 9),
-       usbip_debug_stub_rx     = (1 << 10),
-       usbip_debug_stub_tx     = (1 << 11),
-
-       usbip_debug_vhci_rh     = (1 << 8),
-       usbip_debug_vhci_hc     = (1 << 9),
-       usbip_debug_vhci_rx     = (1 << 10),
-       usbip_debug_vhci_tx     = (1 << 11),
-       usbip_debug_vhci_sysfs  = (1 << 12)
-};
-
-#define usbip_dbg_flag_xmit    (usbip_debug_flag & usbip_debug_xmit)
-#define usbip_dbg_flag_vhci_rh (usbip_debug_flag & usbip_debug_vhci_rh)
-#define usbip_dbg_flag_vhci_hc (usbip_debug_flag & usbip_debug_vhci_hc)
-#define usbip_dbg_flag_vhci_rx (usbip_debug_flag & usbip_debug_vhci_rx)
-#define usbip_dbg_flag_vhci_tx (usbip_debug_flag & usbip_debug_vhci_tx)
-#define usbip_dbg_flag_stub_rx (usbip_debug_flag & usbip_debug_stub_rx)
-#define usbip_dbg_flag_stub_tx (usbip_debug_flag & usbip_debug_stub_tx)
-#define usbip_dbg_flag_vhci_sysfs  (usbip_debug_flag & usbip_debug_vhci_sysfs)
-
-extern unsigned long usbip_debug_flag;
-extern struct device_attribute dev_attr_usbip_debug;
-
-#define usbip_dbg_with_flag(flag, fmt, args...)                \
-       do {                                            \
-               if (flag & usbip_debug_flag)            \
-                       pr_debug(fmt, ##args);          \
-       } while (0)
-
-#define usbip_dbg_sysfs(fmt, args...) \
-       usbip_dbg_with_flag(usbip_debug_sysfs, fmt , ##args)
-#define usbip_dbg_xmit(fmt, args...) \
-       usbip_dbg_with_flag(usbip_debug_xmit, fmt , ##args)
-#define usbip_dbg_urb(fmt, args...) \
-       usbip_dbg_with_flag(usbip_debug_urb, fmt , ##args)
-#define usbip_dbg_eh(fmt, args...) \
-       usbip_dbg_with_flag(usbip_debug_eh, fmt , ##args)
-
-#define usbip_dbg_vhci_rh(fmt, args...)        \
-       usbip_dbg_with_flag(usbip_debug_vhci_rh, fmt , ##args)
-#define usbip_dbg_vhci_hc(fmt, args...)        \
-       usbip_dbg_with_flag(usbip_debug_vhci_hc, fmt , ##args)
-#define usbip_dbg_vhci_rx(fmt, args...)        \
-       usbip_dbg_with_flag(usbip_debug_vhci_rx, fmt , ##args)
-#define usbip_dbg_vhci_tx(fmt, args...)        \
-       usbip_dbg_with_flag(usbip_debug_vhci_tx, fmt , ##args)
-#define usbip_dbg_vhci_sysfs(fmt, args...) \
-       usbip_dbg_with_flag(usbip_debug_vhci_sysfs, fmt , ##args)
-
-#define usbip_dbg_stub_cmp(fmt, args...) \
-       usbip_dbg_with_flag(usbip_debug_stub_cmp, fmt , ##args)
-#define usbip_dbg_stub_rx(fmt, args...) \
-       usbip_dbg_with_flag(usbip_debug_stub_rx, fmt , ##args)
-#define usbip_dbg_stub_tx(fmt, args...) \
-       usbip_dbg_with_flag(usbip_debug_stub_tx, fmt , ##args)
-
-/*
- * USB/IP request headers
- *
- * Each request is transferred across the network to its counterpart, which
- * facilitates the normal USB communication. The values contained in the headers
- * are basically the same as in a URB. Currently, four request types are
- * defined:
- *
- *  - USBIP_CMD_SUBMIT: a USB request block, corresponds to usb_submit_urb()
- *    (client to server)
- *
- *  - USBIP_RET_SUBMIT: the result of USBIP_CMD_SUBMIT
- *    (server to client)
- *
- *  - USBIP_CMD_UNLINK: an unlink request of a pending USBIP_CMD_SUBMIT,
- *    corresponds to usb_unlink_urb()
- *    (client to server)
- *
- *  - USBIP_RET_UNLINK: the result of USBIP_CMD_UNLINK
- *    (server to client)
- *
- */
-#define USBIP_CMD_SUBMIT       0x0001
-#define USBIP_CMD_UNLINK       0x0002
-#define USBIP_RET_SUBMIT       0x0003
-#define USBIP_RET_UNLINK       0x0004
-
-#define USBIP_DIR_OUT  0x00
-#define USBIP_DIR_IN   0x01
-
-/**
- * struct usbip_header_basic - data pertinent to every request
- * @command: the usbip request type
- * @seqnum: sequential number that identifies requests; incremented per
- *         connection
- * @devid: specifies a remote USB device uniquely instead of busnum and devnum;
- *        in the stub driver, this value is ((busnum << 16) | devnum)
- * @direction: direction of the transfer
- * @ep: endpoint number
- */
-struct usbip_header_basic {
-       __u32 command;
-       __u32 seqnum;
-       __u32 devid;
-       __u32 direction;
-       __u32 ep;
-} __packed;
-
-/**
- * struct usbip_header_cmd_submit - USBIP_CMD_SUBMIT packet header
- * @transfer_flags: URB flags
- * @transfer_buffer_length: the data size for (in) or (out) transfer
- * @start_frame: initial frame for isochronous or interrupt transfers
- * @number_of_packets: number of isochronous packets
- * @interval: maximum time for the request on the server-side host controller
- * @setup: setup data for a control request
- */
-struct usbip_header_cmd_submit {
-       __u32 transfer_flags;
-       __s32 transfer_buffer_length;
-
-       /* it is difficult for usbip to sync frames (reserved only?) */
-       __s32 start_frame;
-       __s32 number_of_packets;
-       __s32 interval;
-
-       unsigned char setup[8];
-} __packed;
-
-/**
- * struct usbip_header_ret_submit - USBIP_RET_SUBMIT packet header
- * @status: return status of a non-iso request
- * @actual_length: number of bytes transferred
- * @start_frame: initial frame for isochronous or interrupt transfers
- * @number_of_packets: number of isochronous packets
- * @error_count: number of errors for isochronous transfers
- */
-struct usbip_header_ret_submit {
-       __s32 status;
-       __s32 actual_length;
-       __s32 start_frame;
-       __s32 number_of_packets;
-       __s32 error_count;
-} __packed;
-
-/**
- * struct usbip_header_cmd_unlink - USBIP_CMD_UNLINK packet header
- * @seqnum: the URB seqnum to unlink
- */
-struct usbip_header_cmd_unlink {
-       __u32 seqnum;
-} __packed;
-
-/**
- * struct usbip_header_ret_unlink - USBIP_RET_UNLINK packet header
- * @status: return status of the request
- */
-struct usbip_header_ret_unlink {
-       __s32 status;
-} __packed;
-
-/**
- * struct usbip_header - common header for all usbip packets
- * @base: the basic header
- * @u: packet type dependent header
- */
-struct usbip_header {
-       struct usbip_header_basic base;
-
-       union {
-               struct usbip_header_cmd_submit  cmd_submit;
-               struct usbip_header_ret_submit  ret_submit;
-               struct usbip_header_cmd_unlink  cmd_unlink;
-               struct usbip_header_ret_unlink  ret_unlink;
-       } u;
-} __packed;
-
-/*
- * This is the same as usb_iso_packet_descriptor but packed for pdu.
- */
-struct usbip_iso_packet_descriptor {
-       __u32 offset;
-       __u32 length;                   /* expected length */
-       __u32 actual_length;
-       __u32 status;
-} __packed;
-
-enum usbip_side {
-       USBIP_VHCI,
-       USBIP_STUB,
-};
-
-/* event handler */
-#define USBIP_EH_SHUTDOWN      (1 << 0)
-#define USBIP_EH_BYE           (1 << 1)
-#define USBIP_EH_RESET         (1 << 2)
-#define USBIP_EH_UNUSABLE      (1 << 3)
-
-#define SDEV_EVENT_REMOVED   (USBIP_EH_SHUTDOWN | USBIP_EH_RESET | USBIP_EH_BYE)
-#define        SDEV_EVENT_DOWN         (USBIP_EH_SHUTDOWN | USBIP_EH_RESET)
-#define        SDEV_EVENT_ERROR_TCP    (USBIP_EH_SHUTDOWN | USBIP_EH_RESET)
-#define        SDEV_EVENT_ERROR_SUBMIT (USBIP_EH_SHUTDOWN | USBIP_EH_RESET)
-#define        SDEV_EVENT_ERROR_MALLOC (USBIP_EH_SHUTDOWN | USBIP_EH_UNUSABLE)
-
-#define        VDEV_EVENT_REMOVED      (USBIP_EH_SHUTDOWN | USBIP_EH_BYE)
-#define        VDEV_EVENT_DOWN         (USBIP_EH_SHUTDOWN | USBIP_EH_RESET)
-#define        VDEV_EVENT_ERROR_TCP    (USBIP_EH_SHUTDOWN | USBIP_EH_RESET)
-#define        VDEV_EVENT_ERROR_MALLOC (USBIP_EH_SHUTDOWN | USBIP_EH_UNUSABLE)
-
-/* a common structure for stub_device and vhci_device */
-struct usbip_device {
-       enum usbip_side side;
-       enum usbip_device_status status;
-
-       /* lock for status */
-       spinlock_t lock;
-
-       struct socket *tcp_socket;
-
-       struct task_struct *tcp_rx;
-       struct task_struct *tcp_tx;
-
-       unsigned long event;
-       struct task_struct *eh;
-       wait_queue_head_t eh_waitq;
-
-       struct eh_ops {
-               void (*shutdown)(struct usbip_device *);
-               void (*reset)(struct usbip_device *);
-               void (*unusable)(struct usbip_device *);
-       } eh_ops;
-};
-
-#define kthread_get_run(threadfn, data, namefmt, ...)                     \
-({                                                                        \
-       struct task_struct *__k                                            \
-               = kthread_create(threadfn, data, namefmt, ## __VA_ARGS__); \
-       if (!IS_ERR(__k)) {                                                \
-               get_task_struct(__k);                                      \
-               wake_up_process(__k);                                      \
-       }                                                                  \
-       __k;                                                               \
-})
-
-#define kthread_stop_put(k)            \
-       do {                            \
-               kthread_stop(k);        \
-               put_task_struct(k);     \
-       } while (0)
-
-/* usbip_common.c */
-void usbip_dump_urb(struct urb *purb);
-void usbip_dump_header(struct usbip_header *pdu);
-
-int usbip_recv(struct socket *sock, void *buf, int size);
-
-void usbip_pack_pdu(struct usbip_header *pdu, struct urb *urb, int cmd,
-                   int pack);
-void usbip_header_correct_endian(struct usbip_header *pdu, int send);
-
-struct usbip_iso_packet_descriptor*
-usbip_alloc_iso_desc_pdu(struct urb *urb, ssize_t *bufflen);
-
-/* some members of urb must be substituted before. */
-int usbip_recv_iso(struct usbip_device *ud, struct urb *urb);
-void usbip_pad_iso(struct usbip_device *ud, struct urb *urb);
-int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb);
-
-/* usbip_event.c */
-int usbip_start_eh(struct usbip_device *ud);
-void usbip_stop_eh(struct usbip_device *ud);
-void usbip_event_add(struct usbip_device *ud, unsigned long event);
-int usbip_event_happened(struct usbip_device *ud);
-
-static inline int interface_to_busnum(struct usb_interface *interface)
-{
-       struct usb_device *udev = interface_to_usbdev(interface);
-
-       return udev->bus->busnum;
-}
-
-static inline int interface_to_devnum(struct usb_interface *interface)
-{
-       struct usb_device *udev = interface_to_usbdev(interface);
-
-       return udev->devnum;
-}
-
-#endif /* __USBIP_COMMON_H */
diff --git a/drivers/staging/usbip/usbip_event.c b/drivers/staging/usbip/usbip_event.c
deleted file mode 100644 (file)
index 64933b9..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2003-2008 Takahiro Hirofuchi
- *
- * This 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 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/kthread.h>
-#include <linux/export.h>
-
-#include "usbip_common.h"
-
-static int event_handler(struct usbip_device *ud)
-{
-       usbip_dbg_eh("enter\n");
-
-       /*
-        * Events are handled by only this thread.
-        */
-       while (usbip_event_happened(ud)) {
-               usbip_dbg_eh("pending event %lx\n", ud->event);
-
-               /*
-                * NOTE: shutdown must come first.
-                * Shutdown the device.
-                */
-               if (ud->event & USBIP_EH_SHUTDOWN) {
-                       ud->eh_ops.shutdown(ud);
-                       ud->event &= ~USBIP_EH_SHUTDOWN;
-               }
-
-               /* Reset the device. */
-               if (ud->event & USBIP_EH_RESET) {
-                       ud->eh_ops.reset(ud);
-                       ud->event &= ~USBIP_EH_RESET;
-               }
-
-               /* Mark the device as unusable. */
-               if (ud->event & USBIP_EH_UNUSABLE) {
-                       ud->eh_ops.unusable(ud);
-                       ud->event &= ~USBIP_EH_UNUSABLE;
-               }
-
-               /* Stop the error handler. */
-               if (ud->event & USBIP_EH_BYE)
-                       return -1;
-       }
-
-       return 0;
-}
-
-static int event_handler_loop(void *data)
-{
-       struct usbip_device *ud = data;
-
-       while (!kthread_should_stop()) {
-               wait_event_interruptible(ud->eh_waitq,
-                                        usbip_event_happened(ud) ||
-                                        kthread_should_stop());
-               usbip_dbg_eh("wakeup\n");
-
-               if (event_handler(ud) < 0)
-                       break;
-       }
-
-       return 0;
-}
-
-int usbip_start_eh(struct usbip_device *ud)
-{
-       init_waitqueue_head(&ud->eh_waitq);
-       ud->event = 0;
-
-       ud->eh = kthread_run(event_handler_loop, ud, "usbip_eh");
-       if (IS_ERR(ud->eh)) {
-               pr_warn("Unable to start control thread\n");
-               return PTR_ERR(ud->eh);
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(usbip_start_eh);
-
-void usbip_stop_eh(struct usbip_device *ud)
-{
-       if (ud->eh == current)
-               return; /* do not wait for myself */
-
-       kthread_stop(ud->eh);
-       usbip_dbg_eh("usbip_eh has finished\n");
-}
-EXPORT_SYMBOL_GPL(usbip_stop_eh);
-
-void usbip_event_add(struct usbip_device *ud, unsigned long event)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&ud->lock, flags);
-       ud->event |= event;
-       wake_up(&ud->eh_waitq);
-       spin_unlock_irqrestore(&ud->lock, flags);
-}
-EXPORT_SYMBOL_GPL(usbip_event_add);
-
-int usbip_event_happened(struct usbip_device *ud)
-{
-       int happened = 0;
-
-       spin_lock(&ud->lock);
-       if (ud->event != 0)
-               happened = 1;
-       spin_unlock(&ud->lock);
-
-       return happened;
-}
-EXPORT_SYMBOL_GPL(usbip_event_happened);
diff --git a/drivers/staging/usbip/usbip_protocol.txt b/drivers/staging/usbip/usbip_protocol.txt
deleted file mode 100644 (file)
index 16b6fe2..0000000
+++ /dev/null
@@ -1,358 +0,0 @@
-PRELIMINARY DRAFT, MAY CONTAIN MISTAKES!
-28 Jun 2011
-
-The USB/IP protocol follows a server/client architecture. The server exports the
-USB devices and the clients imports them. The device driver for the exported
-USB device runs on the client machine.
-
-The client may ask for the list of the exported USB devices. To get the list the
-client opens a TCP/IP connection towards the server, and sends an OP_REQ_DEVLIST
-packet on top of the TCP/IP connection (so the actual OP_REQ_DEVLIST may be sent
-in one or more pieces at the low level transport layer). The server sends back
-the OP_REP_DEVLIST packet which lists the exported USB devices. Finally the
-TCP/IP connection is closed.
-
- virtual host controller                                 usb host
-      "client"                                           "server"
-  (imports USB devices)                             (exports USB devices)
-          |                                                 |
-          |                  OP_REQ_DEVLIST                 |
-          | ----------------------------------------------> |
-          |                                                 |
-          |                  OP_REP_DEVLIST                 |
-          | <---------------------------------------------- |
-          |                                                 |
-
-Once the client knows the list of exported USB devices it may decide to use one
-of them. First the client opens a TCP/IP connection towards the server and
-sends an OP_REQ_IMPORT packet. The server replies with OP_REP_IMPORT. If the
-import was successful the TCP/IP connection remains open and will be used
-to transfer the URB traffic between the client and the server. The client may
-send two types of packets: the USBIP_CMD_SUBMIT to submit an URB, and
-USBIP_CMD_UNLINK to unlink a previously submitted URB. The answers of the
-server may be USBIP_RET_SUBMIT and USBIP_RET_UNLINK respectively.
-
- virtual host controller                                 usb host
-      "client"                                           "server"
-  (imports USB devices)                             (exports USB devices)
-          |                                                 |
-          |                  OP_REQ_IMPORT                  |
-          | ----------------------------------------------> |
-          |                                                 |
-          |                  OP_REP_IMPORT                  |
-          | <---------------------------------------------- |
-          |                                                 |
-          |                                                 |
-          |            USBIP_CMD_SUBMIT(seqnum = n)         |
-          | ----------------------------------------------> |
-          |                                                 |
-          |            USBIP_RET_SUBMIT(seqnum = n)         |
-          | <---------------------------------------------- |
-          |                        .                        |
-          |                        :                        |
-          |                                                 |
-          |            USBIP_CMD_SUBMIT(seqnum = m)         |
-          | ----------------------------------------------> |
-          |                                                 |
-          |            USBIP_CMD_SUBMIT(seqnum = m+1)       |
-          | ----------------------------------------------> |
-          |                                                 |
-          |            USBIP_CMD_SUBMIT(seqnum = m+2)       |
-          | ----------------------------------------------> |
-          |                                                 |
-          |            USBIP_RET_SUBMIT(seqnum = m)         |
-          | <---------------------------------------------- |
-          |                                                 |
-          |            USBIP_CMD_SUBMIT(seqnum = m+3)       |
-          | ----------------------------------------------> |
-          |                                                 |
-          |            USBIP_RET_SUBMIT(seqnum = m+1)       |
-          | <---------------------------------------------- |
-          |                                                 |
-          |            USBIP_CMD_SUBMIT(seqnum = m+4)       |
-          | ----------------------------------------------> |
-          |                                                 |
-          |            USBIP_RET_SUBMIT(seqnum = m+2)       |
-          | <---------------------------------------------- |
-          |                        .                        |
-          |                        :                        |
-          |                                                 |
-          |               USBIP_CMD_UNLINK                  |
-          | ----------------------------------------------> |
-          |                                                 |
-          |               USBIP_RET_UNLINK                  |
-          | <---------------------------------------------- |
-          |                                                 |
-
-The fields are in network (big endian) byte order meaning that the most significant
-byte (MSB) is stored at the lowest address.
-
-
-OP_REQ_DEVLIST: Retrieve the list of exported USB devices.
-
- Offset    | Length | Value      | Description
------------+--------+------------+---------------------------------------------------
- 0         | 2      | 0x0100     | Binary-coded decimal USBIP version number: v1.0.0
------------+--------+------------+---------------------------------------------------
- 2         | 2      | 0x8005     | Command code: Retrieve the list of exported USB
-           |        |            |   devices.
------------+--------+------------+---------------------------------------------------
- 4         | 4      | 0x00000000 | Status: unused, shall be set to 0
-
-OP_REP_DEVLIST: Reply with the list of exported USB devices.
-
- Offset    | Length | Value      | Description
------------+--------+------------+---------------------------------------------------
- 0         | 2      | 0x0100     | Binary-coded decimal USBIP version number: v1.0.0.
------------+--------+------------+---------------------------------------------------
- 2         | 2      | 0x0005     | Reply code: The list of exported USB devices.
------------+--------+------------+---------------------------------------------------
- 4         | 4      | 0x00000000 | Status: 0 for OK
------------+--------+------------+---------------------------------------------------
- 8         | 4      | n          | Number of exported devices: 0 means no exported
-           |        |            |   devices.
------------+--------+------------+---------------------------------------------------
- 0x0C      |        |            | From now on the exported n devices are described,
-           |        |            |   if any. If no devices are exported the message
-           |        |            |   ends with the previous "number of exported
-           |        |            |   devices" field.
------------+--------+------------+---------------------------------------------------
-           | 256    |            | path: Path of the device on the host exporting the
-           |        |            |   USB device, string closed with zero byte, e.g.
-           |        |            |   "/sys/devices/pci0000:00/0000:00:1d.1/usb3/3-2"
-           |        |            |   The unused bytes shall be filled with zero
-           |        |            |   bytes.
------------+--------+------------+---------------------------------------------------
- 0x10C     | 32     |            | busid: Bus ID of the exported device, string
-           |        |            |   closed with zero byte, e.g. "3-2". The unused
-           |        |            |   bytes shall be filled with zero bytes.
------------+--------+------------+---------------------------------------------------
- 0x12C     | 4      |            | busnum
------------+--------+------------+---------------------------------------------------
- 0x130     | 4      |            | devnum
------------+--------+------------+---------------------------------------------------
- 0x134     | 4      |            | speed
------------+--------+------------+---------------------------------------------------
- 0x138     | 2      |            | idVendor
------------+--------+------------+---------------------------------------------------
- 0x13A     | 2      |            | idProduct
------------+--------+------------+---------------------------------------------------
- 0x13C     | 2      |            | bcdDevice
------------+--------+------------+---------------------------------------------------
- 0x13E     | 1      |            | bDeviceClass
------------+--------+------------+---------------------------------------------------
- 0x13F     | 1      |            | bDeviceSubClass
------------+--------+------------+---------------------------------------------------
- 0x140     | 1      |            | bDeviceProtocol
------------+--------+------------+---------------------------------------------------
- 0x141     | 1      |            | bConfigurationValue
------------+--------+------------+---------------------------------------------------
- 0x142     | 1      |            | bNumConfigurations
------------+--------+------------+---------------------------------------------------
- 0x143     | 1      |            | bNumInterfaces
------------+--------+------------+---------------------------------------------------
- 0x144     |        | m_0        | From now on each interface is described, all
-           |        |            |   together bNumInterfaces times, with the
-           |        |            |   the following 4 fields:
------------+--------+------------+---------------------------------------------------
-           | 1      |            | bInterfaceClass
------------+--------+------------+---------------------------------------------------
- 0x145     | 1      |            | bInterfaceSubClass
------------+--------+------------+---------------------------------------------------
- 0x146     | 1      |            | bInterfaceProtocol
------------+--------+------------+---------------------------------------------------
- 0x147     | 1      |            | padding byte for alignment, shall be set to zero
------------+--------+------------+---------------------------------------------------
- 0xC +     |        |            | The second exported USB device starts at i=1
- i*0x138 + |        |            | with the busid field.
- m_(i-1)*4 |        |            |
-
-OP_REQ_IMPORT: Request to import (attach) a remote USB device.
-
- Offset    | Length | Value      | Description
------------+--------+------------+---------------------------------------------------
- 0         | 2      | 0x0100     | Binary-coded decimal USBIP version number: v1.0.0
------------+--------+------------+---------------------------------------------------
- 2         | 2      | 0x8003     | Command code: import a remote USB device.
------------+--------+------------+---------------------------------------------------
- 4         | 4      | 0x00000000 | Status: unused, shall be set to 0
------------+--------+------------+---------------------------------------------------
- 8         | 32     |            | busid: the busid of the exported device on the
-           |        |            |   remote host. The possible values are taken
-           |        |            |   from the message field OP_REP_DEVLIST.busid.
-           |        |            |   A string closed with zero, the unused bytes
-           |        |            |   shall be filled with zeros.
------------+--------+------------+---------------------------------------------------
-
-OP_REP_IMPORT: Reply to import (attach) a remote USB device.
-
- Offset    | Length | Value      | Description
------------+--------+------------+---------------------------------------------------
- 0         | 2      | 0x0100     | Binary-coded decimal USBIP version number: v1.0.0
------------+--------+------------+---------------------------------------------------
- 2         | 2      | 0x0003     | Reply code: Reply to import.
------------+--------+------------+---------------------------------------------------
- 4         | 4      | 0x00000000 | Status: 0 for OK
-           |        |            |         1 for error
------------+--------+------------+---------------------------------------------------
- 8         |        |            | From now on comes the details of the imported
-           |        |            |   device, if the previous status field was OK (0),
-           |        |            |   otherwise the reply ends with the status field.
------------+--------+------------+---------------------------------------------------
-           | 256    |            | path: Path of the device on the host exporting the
-           |        |            |   USB device, string closed with zero byte, e.g.
-           |        |            |   "/sys/devices/pci0000:00/0000:00:1d.1/usb3/3-2"
-           |        |            |   The unused bytes shall be filled with zero
-           |        |            |   bytes.
------------+--------+------------+---------------------------------------------------
- 0x108     | 32     |            | busid: Bus ID of the exported device, string
-           |        |            |   closed with zero byte, e.g. "3-2". The unused
-           |        |            |   bytes shall be filled with zero bytes.
------------+--------+------------+---------------------------------------------------
- 0x128     | 4      |            | busnum
------------+--------+------------+---------------------------------------------------
- 0x12C     | 4      |            | devnum
------------+--------+------------+---------------------------------------------------
- 0x130     | 4      |            | speed
------------+--------+------------+---------------------------------------------------
- 0x134     | 2      |            | idVendor
------------+--------+------------+---------------------------------------------------
- 0x136     | 2      |            | idProduct
------------+--------+------------+---------------------------------------------------
- 0x138     | 2      |            | bcdDevice
------------+--------+------------+---------------------------------------------------
- 0x139     | 1      |            | bDeviceClass
------------+--------+------------+---------------------------------------------------
- 0x13A     | 1      |            | bDeviceSubClass
------------+--------+------------+---------------------------------------------------
- 0x13B     | 1      |            | bDeviceProtocol
------------+--------+------------+---------------------------------------------------
- 0x13C     | 1      |            | bConfigurationValue
------------+--------+------------+---------------------------------------------------
- 0x13D     | 1      |            | bNumConfigurations
------------+--------+------------+---------------------------------------------------
- 0x13E     | 1      |            | bNumInterfaces
-
-USBIP_CMD_SUBMIT: Submit an URB
-
- Offset    | Length | Value      | Description
------------+--------+------------+---------------------------------------------------
- 0         | 4      | 0x00000001 | command: Submit an URB
------------+--------+------------+---------------------------------------------------
- 4         | 4      |            | seqnum: the sequence number of the URB to submit
------------+--------+------------+---------------------------------------------------
- 8         | 4      |            | devid
------------+--------+------------+---------------------------------------------------
- 0xC       | 4      |            | direction: 0: USBIP_DIR_OUT
-           |        |            |            1: USBIP_DIR_IN
------------+--------+------------+---------------------------------------------------
- 0x10      | 4      |            | ep: endpoint number, possible values are: 0...15
------------+--------+------------+---------------------------------------------------
- 0x14      | 4      |            | transfer_flags: possible values depend on the
-           |        |            |   URB transfer type, see below
------------+--------+------------+---------------------------------------------------
- 0x18      | 4      |            | transfer_buffer_length
------------+--------+------------+---------------------------------------------------
- 0x1C      | 4      |            | start_frame: specify the selected frame to
-           |        |            |   transmit an ISO frame, ignored if URB_ISO_ASAP
-           |        |            |   is specified at transfer_flags
------------+--------+------------+---------------------------------------------------
- 0x20      | 4      |            | number_of_packets: number of ISO packets
------------+--------+------------+---------------------------------------------------
- 0x24      | 4      |            | interval: maximum time for the request on the
-           |        |            |   server-side host controller
------------+--------+------------+---------------------------------------------------
- 0x28      | 8      |            | setup: data bytes for USB setup, filled with
-           |        |            |   zeros if not used
------------+--------+------------+---------------------------------------------------
- 0x30      |        |            | URB data. For ISO transfers the padding between
-           |        |            |   each ISO packets is not transmitted.
-
-
-  Allowed transfer_flags  | value      | control | interrupt | bulk     | isochronous
- -------------------------+------------+---------+-----------+----------+-------------
-  URB_SHORT_NOT_OK        | 0x00000001 | only in | only in   | only in  | no
-  URB_ISO_ASAP            | 0x00000002 | no      | no        | no       | yes
-  URB_NO_TRANSFER_DMA_MAP | 0x00000004 | yes     | yes       | yes      | yes
-  URB_NO_FSBR             | 0x00000020 | yes     | no        | no       | no
-  URB_ZERO_PACKET         | 0x00000040 | no      | no        | only out | no
-  URB_NO_INTERRUPT        | 0x00000080 | yes     | yes       | yes      | yes
-  URB_FREE_BUFFER         | 0x00000100 | yes     | yes       | yes      | yes
-  URB_DIR_MASK            | 0x00000200 | yes     | yes       | yes      | yes
-
-
-USBIP_RET_SUBMIT: Reply for submitting an URB
-
- Offset    | Length | Value      | Description
------------+--------+------------+---------------------------------------------------
- 0         | 4      | 0x00000003 | command
------------+--------+------------+---------------------------------------------------
- 4         | 4      |            | seqnum: URB sequence number
------------+--------+------------+---------------------------------------------------
- 8         | 4      |            | devid
------------+--------+------------+---------------------------------------------------
- 0xC       | 4      |            | direction: 0: USBIP_DIR_OUT
-           |        |            |            1: USBIP_DIR_IN
------------+--------+------------+---------------------------------------------------
- 0x10      | 4      |            | ep: endpoint number
------------+--------+------------+---------------------------------------------------
- 0x14      | 4      |            | status: zero for successful URB transaction,
-           |        |            |   otherwise some kind of error happened.
------------+--------+------------+---------------------------------------------------
- 0x18      | 4      | n          | actual_length: number of URB data bytes
------------+--------+------------+---------------------------------------------------
- 0x1C      | 4      |            | start_frame: for an ISO frame the actually
-           |        |            |   selected frame for transmit.
------------+--------+------------+---------------------------------------------------
- 0x20      | 4      |            | number_of_packets
------------+--------+------------+---------------------------------------------------
- 0x24      | 4      |            | error_count
------------+--------+------------+---------------------------------------------------
- 0x28      | 8      |            | setup: data bytes for USB setup, filled with
-           |        |            |   zeros if not used
------------+--------+------------+---------------------------------------------------
- 0x30      | n      |            | URB data bytes. For ISO transfers the padding
-           |        |            |   between each ISO packets is not transmitted.
-
-USBIP_CMD_UNLINK: Unlink an URB
-
- Offset    | Length | Value      | Description
------------+--------+------------+---------------------------------------------------
- 0         | 4      | 0x00000002 | command: URB unlink command
------------+--------+------------+---------------------------------------------------
- 4         | 4      |            | seqnum: URB sequence number to unlink: FIXME: is this so?
------------+--------+------------+---------------------------------------------------
- 8         | 4      |            | devid
------------+--------+------------+---------------------------------------------------
- 0xC       | 4      |            | direction: 0: USBIP_DIR_OUT
-           |        |            |            1: USBIP_DIR_IN
------------+--------+------------+---------------------------------------------------
- 0x10      | 4      |            | ep: endpoint number: zero
------------+--------+------------+---------------------------------------------------
- 0x14      | 4      |            | seqnum: the URB sequence number given previously
-           |        |            |   at USBIP_CMD_SUBMIT.seqnum field
------------+--------+------------+---------------------------------------------------
- 0x30      | n      |            | URB data bytes. For ISO transfers the padding
-           |        |            |   between each ISO packets is not transmitted.
-
-USBIP_RET_UNLINK: Reply for URB unlink
-
- Offset    | Length | Value      | Description
------------+--------+------------+---------------------------------------------------
- 0         | 4      | 0x00000004 | command: reply for the URB unlink command
------------+--------+------------+---------------------------------------------------
- 4         | 4      |            | seqnum: the unlinked URB sequence number
------------+--------+------------+---------------------------------------------------
- 8         | 4      |            | devid
------------+--------+------------+---------------------------------------------------
- 0xC       | 4      |            | direction: 0: USBIP_DIR_OUT
-           |        |            |            1: USBIP_DIR_IN
------------+--------+------------+---------------------------------------------------
- 0x10      | 4      |            | ep: endpoint number
------------+--------+------------+---------------------------------------------------
- 0x14      | 4      |            | status: This is the value contained in the
-           |        |            |   urb->status in the URB completition handler.
-           |        |            |   FIXME: a better explanation needed.
------------+--------+------------+---------------------------------------------------
- 0x30      | n      |            | URB data bytes. For ISO transfers the padding
-           |        |            |   between each ISO packets is not transmitted.
diff --git a/drivers/staging/usbip/userspace/.gitignore b/drivers/staging/usbip/userspace/.gitignore
deleted file mode 100644 (file)
index 9aad9e3..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-Makefile
-Makefile.in
-aclocal.m4
-autom4te.cache/
-config.guess
-config.h
-config.h.in
-config.log
-config.status
-config.sub
-configure
-depcomp
-install-sh
-libsrc/Makefile
-libsrc/Makefile.in
-libtool
-ltmain.sh
-missing
-src/Makefile
-src/Makefile.in
-stamp-h1
-libsrc/libusbip.la
-libsrc/libusbip_la-names.lo
-libsrc/libusbip_la-usbip_common.lo
-libsrc/libusbip_la-usbip_host_driver.lo
-libsrc/libusbip_la-vhci_driver.lo
-src/usbip
-src/usbipd
diff --git a/drivers/staging/usbip/userspace/AUTHORS b/drivers/staging/usbip/userspace/AUTHORS
deleted file mode 100644 (file)
index a27ea8d..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-Takahiro Hirofuchi
-Robert Leibl
-matt mooney <mfm@muteddisk.com>
diff --git a/drivers/staging/usbip/userspace/COPYING b/drivers/staging/usbip/userspace/COPYING
deleted file mode 100644 (file)
index c5611e4..0000000
+++ /dev/null
@@ -1,340 +0,0 @@
-                   GNU GENERAL PUBLIC LICENSE
-                      Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
-     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-                           Preamble
-
-  The licenses for most software are designed to take away your
-freedom to share and change it.  By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users.  This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it.  (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.)  You can apply it to
-your programs, too.
-
-  When we speak of free software, we are referring to freedom, not
-price.  Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
-  To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
-  For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have.  You must make sure that they, too, receive or can get the
-source code.  And you must show them these terms so they know their
-rights.
-
-  We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
-  Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software.  If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
-  Finally, any free program is threatened constantly by software
-patents.  We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary.  To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
-  The precise terms and conditions for copying, distribution and
-modification follow.
-
-                   GNU GENERAL PUBLIC LICENSE
-   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
-  0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License.  The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language.  (Hereinafter, translation is included without limitation in
-the term "modification".)  Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope.  The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
-  1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
-  2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
-    a) You must cause the modified files to carry prominent notices
-    stating that you changed the files and the date of any change.
-
-    b) You must cause any work that you distribute or publish, that in
-    whole or in part contains or is derived from the Program or any
-    part thereof, to be licensed as a whole at no charge to all third
-    parties under the terms of this License.
-
-    c) If the modified program normally reads commands interactively
-    when run, you must cause it, when started running for such
-    interactive use in the most ordinary way, to print or display an
-    announcement including an appropriate copyright notice and a
-    notice that there is no warranty (or else, saying that you provide
-    a warranty) and that users may redistribute the program under
-    these conditions, and telling the user how to view a copy of this
-    License.  (Exception: if the Program itself is interactive but
-    does not normally print such an announcement, your work based on
-    the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole.  If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works.  But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
-  3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
-    a) Accompany it with the complete corresponding machine-readable
-    source code, which must be distributed under the terms of Sections
-    1 and 2 above on a medium customarily used for software interchange; or,
-
-    b) Accompany it with a written offer, valid for at least three
-    years, to give any third party, for a charge no more than your
-    cost of physically performing source distribution, a complete
-    machine-readable copy of the corresponding source code, to be
-    distributed under the terms of Sections 1 and 2 above on a medium
-    customarily used for software interchange; or,
-
-    c) Accompany it with the information you received as to the offer
-    to distribute corresponding source code.  (This alternative is
-    allowed only for noncommercial distribution and only if you
-    received the program in object code or executable form with such
-    an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it.  For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable.  However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
-  4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License.  Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
-  5. You are not required to accept this License, since you have not
-signed it.  However, nothing else grants you permission to modify or
-distribute the Program or its derivative works.  These actions are
-prohibited by law if you do not accept this License.  Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
-  6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions.  You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
-  7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License.  If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all.  For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices.  Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
-  8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded.  In such case, this License incorporates
-the limitation as if written in the body of this License.
-
-  9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time.  Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number.  If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation.  If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
-  10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission.  For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this.  Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
-                           NO WARRANTY
-
-  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
-  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
-                    END OF TERMS AND CONDITIONS
-
-           How to Apply These Terms to Your New Programs
-
-  If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
-  To do so, attach the following notices to the program.  It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-    <one line to give the program's name and a brief idea of what it does.>
-    Copyright (C) <year>  <name of author>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
-    Gnomovision version 69, Copyright (C) year  name of author
-    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
-    This is free software, and you are welcome to redistribute it
-    under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License.  Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary.  Here is a sample; alter the names:
-
-  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
-  `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
-  <signature of Ty Coon>, 1 April 1989
-  Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs.  If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library.  If this is what you want to do, use the GNU Library General
-Public License instead of this License.
diff --git a/drivers/staging/usbip/userspace/INSTALL b/drivers/staging/usbip/userspace/INSTALL
deleted file mode 100644 (file)
index d3c5b40..0000000
+++ /dev/null
@@ -1,237 +0,0 @@
-Installation Instructions
-*************************
-
-Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
-2006, 2007 Free Software Foundation, Inc.
-
-This file is free documentation; the Free Software Foundation gives
-unlimited permission to copy, distribute and modify it.
-
-Basic Installation
-==================
-
-Briefly, the shell commands `./configure; make; make install' should
-configure, build, and install this package.  The following
-more-detailed instructions are generic; see the `README' file for
-instructions specific to this package.
-
-   The `configure' shell script attempts to guess correct values for
-various system-dependent variables used during compilation.  It uses
-those values to create a `Makefile' in each directory of the package.
-It may also create one or more `.h' files containing system-dependent
-definitions.  Finally, it creates a shell script `config.status' that
-you can run in the future to recreate the current configuration, and a
-file `config.log' containing compiler output (useful mainly for
-debugging `configure').
-
-   It can also use an optional file (typically called `config.cache'
-and enabled with `--cache-file=config.cache' or simply `-C') that saves
-the results of its tests to speed up reconfiguring.  Caching is
-disabled by default to prevent problems with accidental use of stale
-cache files.
-
-   If you need to do unusual things to compile the package, please try
-to figure out how `configure' could check whether to do them, and mail
-diffs or instructions to the address given in the `README' so they can
-be considered for the next release.  If you are using the cache, and at
-some point `config.cache' contains results you don't want to keep, you
-may remove or edit it.
-
-   The file `configure.ac' (or `configure.in') is used to create
-`configure' by a program called `autoconf'.  You need `configure.ac' if
-you want to change it or regenerate `configure' using a newer version
-of `autoconf'.
-
-The simplest way to compile this package is:
-
-  1. `cd' to the directory containing the package's source code and type
-     `./configure' to configure the package for your system.
-
-     Running `configure' might take a while.  While running, it prints
-     some messages telling which features it is checking for.
-
-  2. Type `make' to compile the package.
-
-  3. Optionally, type `make check' to run any self-tests that come with
-     the package.
-
-  4. Type `make install' to install the programs and any data files and
-     documentation.
-
-  5. You can remove the program binaries and object files from the
-     source code directory by typing `make clean'.  To also remove the
-     files that `configure' created (so you can compile the package for
-     a different kind of computer), type `make distclean'.  There is
-     also a `make maintainer-clean' target, but that is intended mainly
-     for the package's developers.  If you use it, you may have to get
-     all sorts of other programs in order to regenerate files that came
-     with the distribution.
-
-  6. Often, you can also type `make uninstall' to remove the installed
-     files again.
-
-Compilers and Options
-=====================
-
-Some systems require unusual options for compilation or linking that the
-`configure' script does not know about.  Run `./configure --help' for
-details on some of the pertinent environment variables.
-
-   You can give `configure' initial values for configuration parameters
-by setting variables in the command line or in the environment.  Here
-is an example:
-
-     ./configure CC=c99 CFLAGS=-g LIBS=-lposix
-
-   *Note Defining Variables::, for more details.
-
-Compiling For Multiple Architectures
-====================================
-
-You can compile the package for more than one kind of computer at the
-same time, by placing the object files for each architecture in their
-own directory.  To do this, you can use GNU `make'.  `cd' to the
-directory where you want the object files and executables to go and run
-the `configure' script.  `configure' automatically checks for the
-source code in the directory that `configure' is in and in `..'.
-
-   With a non-GNU `make', it is safer to compile the package for one
-architecture at a time in the source code directory.  After you have
-installed the package for one architecture, use `make distclean' before
-reconfiguring for another architecture.
-
-Installation Names
-==================
-
-By default, `make install' installs the package's commands under
-`/usr/local/bin', include files under `/usr/local/include', etc.  You
-can specify an installation prefix other than `/usr/local' by giving
-`configure' the option `--prefix=PREFIX'.
-
-   You can specify separate installation prefixes for
-architecture-specific files and architecture-independent files.  If you
-pass the option `--exec-prefix=PREFIX' to `configure', the package uses
-PREFIX as the prefix for installing programs and libraries.
-Documentation and other data files still use the regular prefix.
-
-   In addition, if you use an unusual directory layout you can give
-options like `--bindir=DIR' to specify different values for particular
-kinds of files.  Run `configure --help' for a list of the directories
-you can set and what kinds of files go in them.
-
-   If the package supports it, you can cause programs to be installed
-with an extra prefix or suffix on their names by giving `configure' the
-option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
-
-Optional Features
-=================
-
-Some packages pay attention to `--enable-FEATURE' options to
-`configure', where FEATURE indicates an optional part of the package.
-They may also pay attention to `--with-PACKAGE' options, where PACKAGE
-is something like `gnu-as' or `x' (for the X Window System).  The
-`README' should mention any `--enable-' and `--with-' options that the
-package recognizes.
-
-   For packages that use the X Window System, `configure' can usually
-find the X include and library files automatically, but if it doesn't,
-you can use the `configure' options `--x-includes=DIR' and
-`--x-libraries=DIR' to specify their locations.
-
-Specifying the System Type
-==========================
-
-There may be some features `configure' cannot figure out automatically,
-but needs to determine by the type of machine the package will run on.
-Usually, assuming the package is built to be run on the _same_
-architectures, `configure' can figure that out, but if it prints a
-message saying it cannot guess the machine type, give it the
-`--build=TYPE' option.  TYPE can either be a short name for the system
-type, such as `sun4', or a canonical name which has the form:
-
-     CPU-COMPANY-SYSTEM
-
-where SYSTEM can have one of these forms:
-
-     OS KERNEL-OS
-
-   See the file `config.sub' for the possible values of each field.  If
-`config.sub' isn't included in this package, then this package doesn't
-need to know the machine type.
-
-   If you are _building_ compiler tools for cross-compiling, you should
-use the option `--target=TYPE' to select the type of system they will
-produce code for.
-
-   If you want to _use_ a cross compiler, that generates code for a
-platform different from the build platform, you should specify the
-"host" platform (i.e., that on which the generated programs will
-eventually be run) with `--host=TYPE'.
-
-Sharing Defaults
-================
-
-If you want to set default values for `configure' scripts to share, you
-can create a site shell script called `config.site' that gives default
-values for variables like `CC', `cache_file', and `prefix'.
-`configure' looks for `PREFIX/share/config.site' if it exists, then
-`PREFIX/etc/config.site' if it exists.  Or, you can set the
-`CONFIG_SITE' environment variable to the location of the site script.
-A warning: not all `configure' scripts look for a site script.
-
-Defining Variables
-==================
-
-Variables not defined in a site shell script can be set in the
-environment passed to `configure'.  However, some packages may run
-configure again during the build, and the customized values of these
-variables may be lost.  In order to avoid this problem, you should set
-them in the `configure' command line, using `VAR=value'.  For example:
-
-     ./configure CC=/usr/local2/bin/gcc
-
-causes the specified `gcc' to be used as the C compiler (unless it is
-overridden in the site shell script).
-
-Unfortunately, this technique does not work for `CONFIG_SHELL' due to
-an Autoconf bug.  Until the bug is fixed you can use this workaround:
-
-     CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
-
-`configure' Invocation
-======================
-
-`configure' recognizes the following options to control how it operates.
-
-`--help'
-`-h'
-     Print a summary of the options to `configure', and exit.
-
-`--version'
-`-V'
-     Print the version of Autoconf used to generate the `configure'
-     script, and exit.
-
-`--cache-file=FILE'
-     Enable the cache: use and save the results of the tests in FILE,
-     traditionally `config.cache'.  FILE defaults to `/dev/null' to
-     disable caching.
-
-`--config-cache'
-`-C'
-     Alias for `--cache-file=config.cache'.
-
-`--quiet'
-`--silent'
-`-q'
-     Do not print messages saying which checks are being made.  To
-     suppress all normal output, redirect it to `/dev/null' (any error
-     messages will still be shown).
-
-`--srcdir=DIR'
-     Look for the package's source code in directory DIR.  Usually
-     `configure' can determine that directory automatically.
-
-`configure' also accepts some other, not widely useful, options.  Run
-`configure --help' for more details.
-
diff --git a/drivers/staging/usbip/userspace/Makefile.am b/drivers/staging/usbip/userspace/Makefile.am
deleted file mode 100644 (file)
index 66f8bf0..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-SUBDIRS := libsrc src
-includedir = @includedir@/usbip
-include_HEADERS := $(addprefix libsrc/, \
-                    usbip_common.h vhci_driver.h usbip_host_driver.h)
-
-dist_man_MANS := $(addprefix doc/, usbip.8 usbipd.8)
diff --git a/drivers/staging/usbip/userspace/README b/drivers/staging/usbip/userspace/README
deleted file mode 100644 (file)
index 831f49f..0000000
+++ /dev/null
@@ -1,202 +0,0 @@
-#
-# README for usbip-utils
-#
-# Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
-#               2005-2008 Takahiro Hirofuchi
-
-
-[Requirements]
-    - USB/IP device drivers
-       Found in the staging directory of the Linux kernel.
-
-    - libudev >= 2.0
-       libudev library
-
-    - libwrap0-dev
-       tcp wrapper library
-
-    - gcc >= 4.0
-
-    - libtool, automake >= 1.9, autoconf >= 2.5.0, pkg-config
-
-[Optional]
-    - hwdata
-        Contains USB device identification data.
-
-
-[Install]
-    0. Generate configuration scripts.
-       $ ./autogen.sh
-
-    1. Compile & install the userspace utilities.
-       $ ./configure [--with-tcp-wrappers=no] [--with-usbids-dir=<dir>]
-       $ make install
-
-    2. Compile & install USB/IP drivers.
-
-
-[Usage]
-    server:# (Physically attach your USB device.)
-
-    server:# insmod usbip-core.ko
-    server:# insmod usbip-host.ko
-
-    server:# usbipd -D
-       - Start usbip daemon.
-
-    server:# usbip list -l
-       - List driver assignments for USB devices.
-
-    server:# usbip bind --busid 1-2
-       - Bind usbip-host.ko to the device with busid 1-2.
-       - The USB device 1-2 is now exportable to other hosts!
-       - Use `usbip unbind --busid 1-2' to stop exporting the device.
-
-    client:# insmod usbip-core.ko
-    client:# insmod vhci-hcd.ko
-
-    client:# usbip list --remote <host>
-       - List exported USB devices on the <host>.
-
-    client:# usbip attach --remote <host> --busid 1-2
-       - Connect the remote USB device.
-
-    client:# usbip port
-       - Show virtual port status.
-
-    client:# usbip detach --port <port>
-       - Detach the USB device.
-
-
-[Example]
----------------------------
-       SERVER SIDE
----------------------------
-Physically attach your USB devices to this host.
-
-    trois:# insmod path/to/usbip-core.ko
-    trois:# insmod path/to/usbip-host.ko
-    trois:# usbipd -D
-
-In another terminal, let's look up what USB devices are physically
-attached to this host.
-
-    trois:# usbip list -l
-    Local USB devices
-    =================
-     - busid 1-1 (05a9:a511)
-            1-1:1.0 -> ov511
-
-     - busid 3-2 (0711:0902)
-            3-2:1.0 -> none
-
-     - busid 3-3.1 (08bb:2702)
-            3-3.1:1.0 -> snd-usb-audio
-            3-3.1:1.1 -> snd-usb-audio
-
-     - busid 3-3.2 (04bb:0206)
-            3-3.2:1.0 -> usb-storage
-
-     - busid 3-3 (0409:0058)
-            3-3:1.0 -> hub
-
-     - busid 4-1 (046d:08b2)
-            4-1:1.0 -> none
-            4-1:1.1 -> none
-            4-1:1.2 -> none
-
-     - busid 5-2 (058f:9254)
-            5-2:1.0 -> hub
-
-A USB storage device of busid 3-3.2 is now bound to the usb-storage
-driver. To export this device, we first mark the device as
-"exportable"; the device is bound to the usbip-host driver. Please
-remember you can not export a USB hub.
-
-Mark the device of busid 3-3.2 as exportable:
-
-    trois:# usbip --debug bind --busid 3-3.2
-    ...
-    usbip debug: usbip_bind.c:162:[unbind_other] 3-3.2:1.0 -> usb-storage
-    ...
-    bind device on busid 3-3.2: complete
-
-    trois:# usbip list -l
-    Local USB devices
-    =================
-    ...
-
-     - busid 3-3.2 (04bb:0206)
-            3-3.2:1.0 -> usbip-host
-    ...
-
----------------------------
-       CLIENT SIDE
----------------------------
-First, let's list available remote devices that are marked as
-exportable on the host.
-
-    deux:# insmod path/to/usbip-core.ko
-    deux:# insmod path/to/vhci-hcd.ko
-
-    deux:# usbip list --remote 10.0.0.3
-    Exportable USB devices
-    ======================
-     - 10.0.0.3
-           1-1: Prolific Technology, Inc. : unknown product (067b:3507)
-              : /sys/devices/pci0000:00/0000:00:1f.2/usb1/1-1
-              : (Defined at Interface level) / unknown subclass / unknown protocol (00/00/00)
-              :  0 - Mass Storage / SCSI / Bulk (Zip) (08/06/50)
-
-       1-2.2.1: Apple Computer, Inc. : unknown product (05ac:0203)
-              : /sys/devices/pci0000:00/0000:00:1f.2/usb1/1-2/1-2.2/1-2.2.1
-              : (Defined at Interface level) / unknown subclass / unknown protocol (00/00/00)
-              :  0 - Human Interface Devices / Boot Interface Subclass / Keyboard (03/01/01)
-
-       1-2.2.3: OmniVision Technologies, Inc. : OV511+ WebCam (05a9:a511)
-              : /sys/devices/pci0000:00/0000:00:1f.2/usb1/1-2/1-2.2/1-2.2.3
-              : (Defined at Interface level) / unknown subclass / unknown protocol (00/00/00)
-              :  0 - Vendor Specific Class / unknown subclass / unknown protocol (ff/00/00)
-
-           3-1: Logitech, Inc. : QuickCam Pro 4000 (046d:08b2)
-              : /sys/devices/pci0000:00/0000:00:1e.0/0000:02:0a.0/usb3/3-1
-              : (Defined at Interface level) / unknown subclass / unknown protocol (00/00/00)
-              :  0 - Data / unknown subclass / unknown protocol (0a/ff/00)
-              :  1 - Audio / Control Device / unknown protocol (01/01/00)
-              :  2 - Audio / Streaming / unknown protocol (01/02/00)
-
-Attach a remote USB device:
-
-    deux:# usbip attach --remote 10.0.0.3 --busid 1-1
-    port 0 attached
-
-Show the devices attached to this client:
-
-    deux:# usbip port
-    Port 00: <Port in Use> at Full Speed(12Mbps)
-          Prolific Technology, Inc. : unknown product (067b:3507)
-          6-1 -> usbip://10.0.0.3:3240/1-1  (remote bus/dev 001/004)
-          6-1:1.0 used by usb-storage
-                         /sys/class/scsi_device/0:0:0:0/device
-                         /sys/class/scsi_host/host0/device
-                         /sys/block/sda/device
-
-Detach the imported device:
-
-    deux:# usbip detach --port 0
-    port 0 detached
-
-
-[Checklist]
-    - See 'Debug Tips' on the project wiki.
-       - http://usbip.wiki.sourceforge.net/how-to-debug-usbip
-    - usbip-host.ko must be bound to the target device.
-       - See /proc/bus/usb/devices and find "Driver=..." lines of the device.
-    - Shutdown firewall.
-       - usbip now uses TCP port 3240.
-    - Disable SELinux.
-    - Check the kernel and daemon messages.
-
-
-[Contact]
-    Mailing List: linux-usb@vger.kernel.org
diff --git a/drivers/staging/usbip/userspace/autogen.sh b/drivers/staging/usbip/userspace/autogen.sh
deleted file mode 100755 (executable)
index e1112d3..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/sh -x
-
-#aclocal
-#autoheader
-#libtoolize --copy --force
-#automake-1.9 -acf
-#autoconf
-
-autoreconf -i -f -v
diff --git a/drivers/staging/usbip/userspace/cleanup.sh b/drivers/staging/usbip/userspace/cleanup.sh
deleted file mode 100755 (executable)
index 955c3cc..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/sh
-
-if [ -r Makefile ]; then
-       make distclean
-fi
-
-FILES="aclocal.m4 autom4te.cache compile config.guess config.h.in config.log \
-       config.status config.sub configure cscope.out depcomp install-sh      \
-       libsrc/Makefile libsrc/Makefile.in libtool ltmain.sh Makefile         \
-       Makefile.in missing src/Makefile src/Makefile.in"
-
-rm -vRf $FILES
diff --git a/drivers/staging/usbip/userspace/configure.ac b/drivers/staging/usbip/userspace/configure.ac
deleted file mode 100644 (file)
index 607d05c..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-dnl Process this file with autoconf to produce a configure script.
-
-AC_PREREQ(2.59)
-AC_INIT([usbip-utils], [2.0], [linux-usb@vger.kernel.org])
-AC_DEFINE([USBIP_VERSION], [0x00000111], [binary-coded decimal version number])
-
-CURRENT=0
-REVISION=1
-AGE=0
-AC_SUBST([LIBUSBIP_VERSION], [$CURRENT:$REVISION:$AGE], [library version])
-
-AC_CONFIG_SRCDIR([src/usbipd.c])
-AC_CONFIG_HEADERS([config.h])
-
-AM_INIT_AUTOMAKE([foreign])
-LT_INIT
-
-# Silent build for automake >= 1.11
-m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
-
-AC_SUBST([EXTRA_CFLAGS], ["-Wall -Werror -Wextra -std=gnu99"])
-
-# Checks for programs.
-AC_PROG_CC
-AC_PROG_INSTALL
-AC_PROG_MAKE_SET
-
-# Checks for header files.
-AC_HEADER_DIRENT
-AC_HEADER_STDC
-AC_CHECK_HEADERS([arpa/inet.h fcntl.h netdb.h netinet/in.h stdint.h stdlib.h dnl
-                 string.h sys/socket.h syslog.h unistd.h])
-
-# Checks for typedefs, structures, and compiler characteristics.
-AC_TYPE_INT32_T
-AC_TYPE_SIZE_T
-AC_TYPE_SSIZE_T
-AC_TYPE_UINT16_T
-AC_TYPE_UINT32_T
-AC_TYPE_UINT8_T
-
-# Checks for library functions.
-AC_FUNC_REALLOC
-AC_CHECK_FUNCS([memset mkdir regcomp socket strchr strerror strstr dnl
-               strtoul])
-
-AC_CHECK_HEADER([libudev.h],
-               [AC_CHECK_LIB([udev], [udev_new],
-                             [LIBS="$LIBS -ludev"],
-                             [AC_MSG_ERROR([Missing udev library!])])],
-               [AC_MSG_ERROR([Missing /usr/include/libudev.h])])
-
-# Checks for libwrap library.
-AC_MSG_CHECKING([whether to use the libwrap (TCP wrappers) library])
-AC_ARG_WITH([tcp-wrappers],
-           [AS_HELP_STRING([--with-tcp-wrappers],
-                           [use the libwrap (TCP wrappers) library])],
-           dnl [ACTION-IF-GIVEN]
-           [if test "$withval" = "yes"; then
-                    AC_MSG_RESULT([yes])
-                    AC_MSG_CHECKING([for hosts_access in -lwrap])
-                    saved_LIBS="$LIBS"
-                    LIBS="-lwrap $saved_LIBS"
-                    AC_TRY_LINK(
-                      [int hosts_access(); int allow_severity, deny_severity;],
-                      [hosts_access()],
-                      [AC_MSG_RESULT([yes]);
-                       AC_DEFINE([HAVE_LIBWRAP], [1],
-                                 [use tcp wrapper]) wrap_LIB="-lwrap"],
-                      [AC_MSG_RESULT([not found]); exit 1])
-            else
-                    AC_MSG_RESULT([no]);
-            fi],
-           dnl [ACTION-IF-NOT-GIVEN]
-           [AC_MSG_RESULT([(default)])
-            AC_MSG_CHECKING([for hosts_access in -lwrap])
-            saved_LIBS="$LIBS"
-            LIBS="-lwrap $saved_LIBS"
-            AC_TRY_LINK(
-              [int hosts_access(); int allow_severity, deny_severity;],
-              [hosts_access()],
-              [AC_MSG_RESULT([yes]);
-               AC_DEFINE([HAVE_LIBWRAP], [1], [use tcp wrapper])],
-              [AC_MSG_RESULT([no]); LIBS="$saved_LIBS"])])
-
-# Sets directory containing usb.ids.
-AC_ARG_WITH([usbids-dir],
-           [AS_HELP_STRING([--with-usbids-dir=DIR],
-              [where usb.ids is found (default /usr/share/hwdata/)])],
-           [USBIDS_DIR=$withval], [USBIDS_DIR="/usr/share/hwdata/"])
-AC_SUBST([USBIDS_DIR])
-
-# use _FORTIFY_SOURCE
-AC_MSG_CHECKING([whether to use fortify])
-AC_ARG_WITH([fortify],
-           [AS_HELP_STRING([--with-fortify],
-                           [use _FORTIFY_SROUCE option when compiling)])],
-                           dnl [ACTION-IF-GIVEN]
-                           [if test "$withval" = "yes"; then
-                               AC_MSG_RESULT([yes])
-                               CFLAGS="$CFLAGS -D_FORTIFY_SOURCE -O"
-                            else
-                               AC_MSG_RESULT([no])
-                               CFLAGS="$CFLAGS -U_FORTIFY_SOURCE"
-                            fi
-                           ],
-                           dnl [ACTION-IF-NOT-GIVEN]
-                           [AC_MSG_RESULT([default])])
-
-AC_CONFIG_FILES([Makefile libsrc/Makefile src/Makefile])
-AC_OUTPUT
diff --git a/drivers/staging/usbip/userspace/doc/usbip.8 b/drivers/staging/usbip/userspace/doc/usbip.8
deleted file mode 100644 (file)
index a6097be..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-.TH USBIP "8" "February 2009" "usbip" "System Administration Utilities"
-.SH NAME
-usbip \- manage USB/IP devices
-.SH SYNOPSIS
-.B usbip
-[\fIoptions\fR] <\fIcommand\fR> <\fIargs\fR>
-
-.SH DESCRIPTION
-On a USB/IP server, devices can be listed, bound, and unbound using
-this program.  On a USB/IP client, devices exported by USB/IP servers
-can be listed, attached and detached.
-
-.SH OPTIONS
-.HP
-\fB\-\-debug\fR
-.IP
-Print debugging information.
-.PP
-
-.HP
-\fB\-\-log\fR
-.IP
-Log to syslog.
-.PP
-
-.HP
-\fB\-\-tcp-port PORT\fR
-.IP
-Connect to PORT on remote host (used for attach and list --remote).
-.PP
-
-.SH COMMANDS
-.HP
-\fBversion\fR
-.IP
-Show version and exit.
-.PP
-
-.HP
-\fBhelp\fR [\fIcommand\fR]
-.IP
-Print the program help message, or help on a specific command, and
-then exit.
-.PP
-
-.HP
-\fBattach\fR \-\-remote=<\fIhost\fR> \-\-busid=<\fIbus_id\fR>
-.IP
-Attach a remote USB device.
-.PP
-
-.HP
-\fBdetach\fR \-\-port=<\fIport\fR>
-.IP
-Detach an imported USB device.
-.PP
-
-.HP
-\fBbind\fR \-\-busid=<\fIbusid\fR>
-.IP
-Make a device exportable.
-.PP
-
-.HP
-\fBunbind\fR \-\-busid=<\fIbusid\fR>
-.IP
-Stop exporting a device so it can be used by a local driver.
-.PP
-
-.HP
-\fBlist\fR \-\-remote=<\fIhost\fR>
-.IP
-List USB devices exported by a remote host.
-.PP
-
-.HP
-\fBlist\fR \-\-local
-.IP
-List local USB devices.
-.PP
-
-
-.SH EXAMPLES
-
-    client:# usbip list --remote=server
-        - List exportable usb devices on the server.
-
-    client:# usbip attach --remote=server --busid=1-2
-        - Connect the remote USB device.
-
-    client:# usbip detach --port=0
-        - Detach the usb device.
-
-.SH "SEE ALSO"
-\fBusbipd\fP\fB(8)\fB\fP
diff --git a/drivers/staging/usbip/userspace/doc/usbipd.8 b/drivers/staging/usbip/userspace/doc/usbipd.8
deleted file mode 100644 (file)
index ac4635d..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-.TH USBIP "8" "February 2009" "usbip" "System Administration Utilities"
-.SH NAME
-usbipd \- USB/IP server daemon
-.SH SYNOPSIS
-.B usbipd
-[\fIoptions\fR]
-
-.SH DESCRIPTION
-.B usbipd
-provides USB/IP clients access to exported USB devices.
-
-Devices have to explicitly be exported using
-.B usbip bind
-before usbipd makes them available to other hosts.
-
-The daemon accepts connections from USB/IP clients
-on TCP port 3240 by default.
-
-.SH OPTIONS
-.HP
-\fB\-4\fR, \fB\-\-ipv4\fR
-.IP
-Bind to IPv4. Default is both.
-.PP
-
-.HP
-\fB\-6\fR, \fB\-\-ipv6\fR
-.IP
-Bind to IPv6. Default is both.
-.PP
-
-.HP
-\fB\-D\fR, \fB\-\-daemon\fR
-.IP
-Run as a daemon process.
-.PP
-
-.HP
-\fB\-d\fR, \fB\-\-debug\fR
-.IP
-Print debugging information.
-.PP
-
-.HP
-\fB\-PFILE\fR, \fB\-\-pid FILE\fR
-.IP
-Write process id to FILE.
-.br
-If no FILE specified, use /var/run/usbipd.pid
-.PP
-
-\fB\-tPORT\fR, \fB\-\-tcp\-port PORT\fR
-.IP
-Listen on TCP/IP port PORT.
-.PP
-
-\fB\-h\fR, \fB\-\-help\fR
-.IP
-Print the program help message and exit.
-.PP
-
-.HP
-\fB\-v\fR, \fB\-\-version\fR
-.IP
-Show version.
-.PP
-
-.SH LIMITATIONS
-
-.B usbipd
-offers no authentication or authorization for USB/IP. Any
-USB/IP client can connect and use exported devices.
-
-.SH EXAMPLES
-
-    server:# modprobe usbip
-
-    server:# usbipd -D
-        - Start usbip daemon.
-
-    server:# usbip list --local
-        - List driver assignments for usb devices.
-
-    server:# usbip bind --busid=1-2
-        - Bind usbip-host.ko to the device of busid 1-2.
-        - A usb device 1-2 is now exportable to other hosts!
-        - Use 'usbip unbind --busid=1-2' when you want to shutdown exporting and use the device locally.
-
-.SH "SEE ALSO"
-\fBusbip\fP\fB(8)\fB\fP
-
diff --git a/drivers/staging/usbip/userspace/libsrc/Makefile.am b/drivers/staging/usbip/userspace/libsrc/Makefile.am
deleted file mode 100644 (file)
index 7c8f8a4..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-libusbip_la_CPPFLAGS = -DUSBIDS_FILE='"@USBIDS_DIR@/usb.ids"'
-libusbip_la_CFLAGS   = @EXTRA_CFLAGS@
-libusbip_la_LDFLAGS  = -version-info @LIBUSBIP_VERSION@
-
-lib_LTLIBRARIES := libusbip.la
-libusbip_la_SOURCES := names.c names.h usbip_host_driver.c usbip_host_driver.h \
-                      usbip_common.c usbip_common.h vhci_driver.c vhci_driver.h \
-                      sysfs_utils.c sysfs_utils.h
diff --git a/drivers/staging/usbip/userspace/libsrc/list.h b/drivers/staging/usbip/userspace/libsrc/list.h
deleted file mode 100644 (file)
index 8d0c936..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-#ifndef _LIST_H
-#define _LIST_H
-
-/* Stripped down implementation of linked list taken
- * from the Linux Kernel.
- */
-
-/*
- * Simple doubly linked list implementation.
- *
- * Some of the internal functions ("__xxx") are useful when
- * manipulating whole lists rather than single entries, as
- * sometimes we already know the next/prev entries and we can
- * generate better code by using them directly rather than
- * using the generic single-entry routines.
- */
-
-struct list_head {
-       struct list_head *next, *prev;
-};
-
-#define LIST_HEAD_INIT(name) { &(name), &(name) }
-
-#define LIST_HEAD(name) \
-       struct list_head name = LIST_HEAD_INIT(name)
-
-static inline void INIT_LIST_HEAD(struct list_head *list)
-{
-       list->next = list;
-       list->prev = list;
-}
-
-/*
- * Insert a new entry between two known consecutive entries.
- *
- * This is only for internal list manipulation where we know
- * the prev/next entries already!
- */
-static inline void __list_add(struct list_head *new,
-                             struct list_head *prev,
-                             struct list_head *next)
-{
-       next->prev = new;
-       new->next = next;
-       new->prev = prev;
-       prev->next = new;
-}
-
-/**
- * list_add - add a new entry
- * @new: new entry to be added
- * @head: list head to add it after
- *
- * Insert a new entry after the specified head.
- * This is good for implementing stacks.
- */
-static inline void list_add(struct list_head *new, struct list_head *head)
-{
-       __list_add(new, head, head->next);
-}
-
-/*
- * Delete a list entry by making the prev/next entries
- * point to each other.
- *
- * This is only for internal list manipulation where we know
- * the prev/next entries already!
- */
-static inline void __list_del(struct list_head * prev, struct list_head * next)
-{
-       next->prev = prev;
-       prev->next = next;
-}
-
-#define POISON_POINTER_DELTA 0
-#define LIST_POISON1  ((void *) 0x00100100 + POISON_POINTER_DELTA)
-#define LIST_POISON2  ((void *) 0x00200200 + POISON_POINTER_DELTA)
-
-/**
- * list_del - deletes entry from list.
- * @entry: the element to delete from the list.
- * Note: list_empty() on entry does not return true after this, the entry is
- * in an undefined state.
- */
-static inline void __list_del_entry(struct list_head *entry)
-{
-       __list_del(entry->prev, entry->next);
-}
-
-static inline void list_del(struct list_head *entry)
-{
-       __list_del(entry->prev, entry->next);
-       entry->next = LIST_POISON1;
-       entry->prev = LIST_POISON2;
-}
-
-/**
- * list_entry - get the struct for this entry
- * @ptr:       the &struct list_head pointer.
- * @type:      the type of the struct this is embedded in.
- * @member:    the name of the list_struct within the struct.
- */
-#define list_entry(ptr, type, member) \
-       container_of(ptr, type, member)
-/**
- * list_for_each       -       iterate over a list
- * @pos:       the &struct list_head to use as a loop cursor.
- * @head:      the head for your list.
- */
-#define list_for_each(pos, head) \
-       for (pos = (head)->next; pos != (head); pos = pos->next)
-
-/**
- * list_for_each_safe - iterate over a list safe against removal of list entry
- * @pos:       the &struct list_head to use as a loop cursor.
- * @n:         another &struct list_head to use as temporary storage
- * @head:      the head for your list.
- */
-#define list_for_each_safe(pos, n, head) \
-       for (pos = (head)->next, n = pos->next; pos != (head); \
-               pos = n, n = pos->next)
-
-#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
-
-/**
- * container_of - cast a member of a structure out to the containing structure
- * @ptr:       the pointer to the member.
- * @type:      the type of the container struct this is embedded in.
- * @member:    the name of the member within the struct.
- *
- */
-#define container_of(ptr, type, member) ({                     \
-       const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
-       (type *)( (char *)__mptr - offsetof(type,member) );})
-
-#endif
diff --git a/drivers/staging/usbip/userspace/libsrc/names.c b/drivers/staging/usbip/userspace/libsrc/names.c
deleted file mode 100644 (file)
index 81ff852..0000000
+++ /dev/null
@@ -1,504 +0,0 @@
-/*
- *      names.c  --  USB name database manipulation routines
- *
- *      Copyright (C) 1999, 2000  Thomas Sailer (sailer@ife.ee.ethz.ch)
- *
- *      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., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- *
- *
- *
- *     Copyright (C) 2005 Takahiro Hirofuchi
- *             - names_deinit() is added.
- *
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <string.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <ctype.h>
-
-#include "names.h"
-#include "usbip_common.h"
-
-struct vendor {
-       struct vendor *next;
-       u_int16_t vendorid;
-       char name[1];
-};
-
-struct product {
-       struct product *next;
-       u_int16_t vendorid, productid;
-       char name[1];
-};
-
-struct class {
-       struct class *next;
-       u_int8_t classid;
-       char name[1];
-};
-
-struct subclass {
-       struct subclass *next;
-       u_int8_t classid, subclassid;
-       char name[1];
-};
-
-struct protocol {
-       struct protocol *next;
-       u_int8_t classid, subclassid, protocolid;
-       char name[1];
-};
-
-struct genericstrtable {
-       struct genericstrtable *next;
-       unsigned int num;
-       char name[1];
-};
-
-
-#define HASH1  0x10
-#define HASH2  0x02
-#define HASHSZ 16
-
-static unsigned int hashnum(unsigned int num)
-{
-       unsigned int mask1 = HASH1 << 27, mask2 = HASH2 << 27;
-
-       for (; mask1 >= HASH1; mask1 >>= 1, mask2 >>= 1)
-               if (num & mask1)
-                       num ^= mask2;
-       return num & (HASHSZ-1);
-}
-
-
-static struct vendor *vendors[HASHSZ] = { NULL, };
-static struct product *products[HASHSZ] = { NULL, };
-static struct class *classes[HASHSZ] = { NULL, };
-static struct subclass *subclasses[HASHSZ] = { NULL, };
-static struct protocol *protocols[HASHSZ] = { NULL, };
-
-const char *names_vendor(u_int16_t vendorid)
-{
-       struct vendor *v;
-
-       v = vendors[hashnum(vendorid)];
-       for (; v; v = v->next)
-               if (v->vendorid == vendorid)
-                       return v->name;
-       return NULL;
-}
-
-const char *names_product(u_int16_t vendorid, u_int16_t productid)
-{
-       struct product *p;
-
-       p = products[hashnum((vendorid << 16) | productid)];
-       for (; p; p = p->next)
-               if (p->vendorid == vendorid && p->productid == productid)
-                       return p->name;
-       return NULL;
-}
-
-const char *names_class(u_int8_t classid)
-{
-       struct class *c;
-
-       c = classes[hashnum(classid)];
-       for (; c; c = c->next)
-               if (c->classid == classid)
-                       return c->name;
-       return NULL;
-}
-
-const char *names_subclass(u_int8_t classid, u_int8_t subclassid)
-{
-       struct subclass *s;
-
-       s = subclasses[hashnum((classid << 8) | subclassid)];
-       for (; s; s = s->next)
-               if (s->classid == classid && s->subclassid == subclassid)
-                       return s->name;
-       return NULL;
-}
-
-const char *names_protocol(u_int8_t classid, u_int8_t subclassid,
-                          u_int8_t protocolid)
-{
-       struct protocol *p;
-
-       p = protocols[hashnum((classid << 16) | (subclassid << 8)
-                             | protocolid)];
-       for (; p; p = p->next)
-               if (p->classid == classid && p->subclassid == subclassid &&
-                   p->protocolid == protocolid)
-                       return p->name;
-       return NULL;
-}
-
-/* add a cleanup function by takahiro */
-struct pool {
-       struct pool *next;
-       void *mem;
-};
-
-static struct pool *pool_head;
-
-static void *my_malloc(size_t size)
-{
-       struct pool *p;
-
-       p = calloc(1, sizeof(struct pool));
-       if (!p)
-               return NULL;
-
-       p->mem = calloc(1, size);
-       if (!p->mem) {
-               free(p);
-               return NULL;
-       }
-
-       p->next = pool_head;
-       pool_head = p;
-
-       return p->mem;
-}
-
-void names_free(void)
-{
-       struct pool *pool;
-
-       if (!pool_head)
-               return;
-
-       for (pool = pool_head; pool != NULL; ) {
-               struct pool *tmp;
-
-               if (pool->mem)
-                       free(pool->mem);
-
-               tmp = pool;
-               pool = pool->next;
-               free(tmp);
-       }
-}
-
-static int new_vendor(const char *name, u_int16_t vendorid)
-{
-       struct vendor *v;
-       unsigned int h = hashnum(vendorid);
-
-       v = vendors[h];
-       for (; v; v = v->next)
-               if (v->vendorid == vendorid)
-                       return -1;
-       v = my_malloc(sizeof(struct vendor) + strlen(name));
-       if (!v)
-               return -1;
-       strcpy(v->name, name);
-       v->vendorid = vendorid;
-       v->next = vendors[h];
-       vendors[h] = v;
-       return 0;
-}
-
-static int new_product(const char *name, u_int16_t vendorid,
-                      u_int16_t productid)
-{
-       struct product *p;
-       unsigned int h = hashnum((vendorid << 16) | productid);
-
-       p = products[h];
-       for (; p; p = p->next)
-               if (p->vendorid == vendorid && p->productid == productid)
-                       return -1;
-       p = my_malloc(sizeof(struct product) + strlen(name));
-       if (!p)
-               return -1;
-       strcpy(p->name, name);
-       p->vendorid = vendorid;
-       p->productid = productid;
-       p->next = products[h];
-       products[h] = p;
-       return 0;
-}
-
-static int new_class(const char *name, u_int8_t classid)
-{
-       struct class *c;
-       unsigned int h = hashnum(classid);
-
-       c = classes[h];
-       for (; c; c = c->next)
-               if (c->classid == classid)
-                       return -1;
-       c = my_malloc(sizeof(struct class) + strlen(name));
-       if (!c)
-               return -1;
-       strcpy(c->name, name);
-       c->classid = classid;
-       c->next = classes[h];
-       classes[h] = c;
-       return 0;
-}
-
-static int new_subclass(const char *name, u_int8_t classid, u_int8_t subclassid)
-{
-       struct subclass *s;
-       unsigned int h = hashnum((classid << 8) | subclassid);
-
-       s = subclasses[h];
-       for (; s; s = s->next)
-               if (s->classid == classid && s->subclassid == subclassid)
-                       return -1;
-       s = my_malloc(sizeof(struct subclass) + strlen(name));
-       if (!s)
-               return -1;
-       strcpy(s->name, name);
-       s->classid = classid;
-       s->subclassid = subclassid;
-       s->next = subclasses[h];
-       subclasses[h] = s;
-       return 0;
-}
-
-static int new_protocol(const char *name, u_int8_t classid, u_int8_t subclassid,
-                       u_int8_t protocolid)
-{
-       struct protocol *p;
-       unsigned int h = hashnum((classid << 16) | (subclassid << 8)
-                                | protocolid);
-
-       p = protocols[h];
-       for (; p; p = p->next)
-               if (p->classid == classid && p->subclassid == subclassid
-                   && p->protocolid == protocolid)
-                       return -1;
-       p = my_malloc(sizeof(struct protocol) + strlen(name));
-       if (!p)
-               return -1;
-       strcpy(p->name, name);
-       p->classid = classid;
-       p->subclassid = subclassid;
-       p->protocolid = protocolid;
-       p->next = protocols[h];
-       protocols[h] = p;
-       return 0;
-}
-
-static void parse(FILE *f)
-{
-       char buf[512], *cp;
-       unsigned int linectr = 0;
-       int lastvendor = -1;
-       int lastclass = -1;
-       int lastsubclass = -1;
-       int lasthut = -1;
-       int lastlang = -1;
-       unsigned int u;
-
-       while (fgets(buf, sizeof(buf), f)) {
-               linectr++;
-               /* remove line ends */
-               cp = strchr(buf, '\r');
-               if (cp)
-                       *cp = 0;
-               cp = strchr(buf, '\n');
-               if (cp)
-                       *cp = 0;
-               if (buf[0] == '#' || !buf[0])
-                       continue;
-               cp = buf;
-               if (buf[0] == 'P' && buf[1] == 'H' && buf[2] == 'Y' &&
-                   buf[3] == 'S' && buf[4] == 'D' &&
-                   buf[5] == 'E' && buf[6] == 'S' && /*isspace(buf[7])*/
-                   buf[7] == ' ') {
-                       continue;
-               }
-               if (buf[0] == 'P' && buf[1] == 'H' &&
-                   buf[2] == 'Y' && /*isspace(buf[3])*/ buf[3] == ' ') {
-                       continue;
-               }
-               if (buf[0] == 'B' && buf[1] == 'I' && buf[2] == 'A' &&
-                   buf[3] == 'S' && /*isspace(buf[4])*/ buf[4] == ' ') {
-                       continue;
-               }
-               if (buf[0] == 'L' && /*isspace(buf[1])*/ buf[1] == ' ') {
-                       lasthut = lastclass = lastvendor = lastsubclass = -1;
-                       /*
-                        * set 1 as pseudo-id to indicate that the parser is
-                        * in a `L' section.
-                        */
-                       lastlang = 1;
-                       continue;
-               }
-               if (buf[0] == 'C' && /*isspace(buf[1])*/ buf[1] == ' ') {
-                       /* class spec */
-                       cp = buf+2;
-                       while (isspace(*cp))
-                               cp++;
-                       if (!isxdigit(*cp)) {
-                               err("Invalid class spec at line %u", linectr);
-                               continue;
-                       }
-                       u = strtoul(cp, &cp, 16);
-                       while (isspace(*cp))
-                               cp++;
-                       if (!*cp) {
-                               err("Invalid class spec at line %u", linectr);
-                               continue;
-                       }
-                       if (new_class(cp, u))
-                               err("Duplicate class spec at line %u class %04x %s",
-                                   linectr, u, cp);
-                       dbg("line %5u class %02x %s", linectr, u, cp);
-                       lasthut = lastlang = lastvendor = lastsubclass = -1;
-                       lastclass = u;
-                       continue;
-               }
-               if (buf[0] == 'A' && buf[1] == 'T' && isspace(buf[2])) {
-                       /* audio terminal type spec */
-                       continue;
-               }
-               if (buf[0] == 'H' && buf[1] == 'C' && buf[2] == 'C'
-                   && isspace(buf[3])) {
-                       /* HID Descriptor bCountryCode */
-                       continue;
-               }
-               if (isxdigit(*cp)) {
-                       /* vendor */
-                       u = strtoul(cp, &cp, 16);
-                       while (isspace(*cp))
-                               cp++;
-                       if (!*cp) {
-                               err("Invalid vendor spec at line %u", linectr);
-                               continue;
-                       }
-                       if (new_vendor(cp, u))
-                               err("Duplicate vendor spec at line %u vendor %04x %s",
-                                   linectr, u, cp);
-                       dbg("line %5u vendor %04x %s", linectr, u, cp);
-                       lastvendor = u;
-                       lasthut = lastlang = lastclass = lastsubclass = -1;
-                       continue;
-               }
-               if (buf[0] == '\t' && isxdigit(buf[1])) {
-                       /* product or subclass spec */
-                       u = strtoul(buf+1, &cp, 16);
-                       while (isspace(*cp))
-                               cp++;
-                       if (!*cp) {
-                               err("Invalid product/subclass spec at line %u",
-                                   linectr);
-                               continue;
-                       }
-                       if (lastvendor != -1) {
-                               if (new_product(cp, lastvendor, u))
-                                       err("Duplicate product spec at line %u product %04x:%04x %s",
-                                           linectr, lastvendor, u, cp);
-                               dbg("line %5u product %04x:%04x %s", linectr,
-                                   lastvendor, u, cp);
-                               continue;
-                       }
-                       if (lastclass != -1) {
-                               if (new_subclass(cp, lastclass, u))
-                                       err("Duplicate subclass spec at line %u class %02x:%02x %s",
-                                           linectr, lastclass, u, cp);
-                               dbg("line %5u subclass %02x:%02x %s", linectr,
-                                   lastclass, u, cp);
-                               lastsubclass = u;
-                               continue;
-                       }
-                       if (lasthut != -1) {
-                               /* do not store hut */
-                               continue;
-                       }
-                       if (lastlang != -1) {
-                               /* do not store langid */
-                               continue;
-                       }
-                       err("Product/Subclass spec without prior Vendor/Class spec at line %u",
-                           linectr);
-                       continue;
-               }
-               if (buf[0] == '\t' && buf[1] == '\t' && isxdigit(buf[2])) {
-                       /* protocol spec */
-                       u = strtoul(buf+2, &cp, 16);
-                       while (isspace(*cp))
-                               cp++;
-                       if (!*cp) {
-                               err("Invalid protocol spec at line %u",
-                                   linectr);
-                               continue;
-                       }
-                       if (lastclass != -1 && lastsubclass != -1) {
-                               if (new_protocol(cp, lastclass, lastsubclass,
-                                                u))
-                                       err("Duplicate protocol spec at line %u class %02x:%02x:%02x %s",
-                                           linectr, lastclass, lastsubclass,
-                                           u, cp);
-                               dbg("line %5u protocol %02x:%02x:%02x %s",
-                                   linectr, lastclass, lastsubclass, u, cp);
-                               continue;
-                       }
-                       err("Protocol spec without prior Class and Subclass spec at line %u",
-                           linectr);
-                       continue;
-               }
-               if (buf[0] == 'H' && buf[1] == 'I' &&
-                   buf[2] == 'D' && /*isspace(buf[3])*/ buf[3] == ' ') {
-                       continue;
-               }
-               if (buf[0] == 'H' && buf[1] == 'U' &&
-                   buf[2] == 'T' && /*isspace(buf[3])*/ buf[3] == ' ') {
-                       lastlang = lastclass = lastvendor = lastsubclass = -1;
-                       /*
-                        * set 1 as pseudo-id to indicate that the parser is
-                        * in a `HUT' section.
-                        */
-                       lasthut = 1;
-                       continue;
-               }
-               if (buf[0] == 'R' && buf[1] == ' ')
-                       continue;
-
-               if (buf[0] == 'V' && buf[1] == 'T')
-                       continue;
-
-               err("Unknown line at line %u", linectr);
-       }
-}
-
-
-int names_init(char *n)
-{
-       FILE *f;
-
-       f = fopen(n, "r");
-       if (!f)
-               return errno;
-
-       parse(f);
-       fclose(f);
-       return 0;
-}
diff --git a/drivers/staging/usbip/userspace/libsrc/names.h b/drivers/staging/usbip/userspace/libsrc/names.h
deleted file mode 100644 (file)
index 6809265..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- *      names.h  --  USB name database manipulation routines
- *
- *      Copyright (C) 1999, 2000  Thomas Sailer (sailer@ife.ee.ethz.ch)
- *
- *      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., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- *
- *     Copyright (C) 2005 Takahiro Hirofuchi
- *            - names_free() is added.
- */
-
-#ifndef _NAMES_H
-#define _NAMES_H
-
-#include <sys/types.h>
-
-/* used by usbip_common.c */
-extern const char *names_vendor(u_int16_t vendorid);
-extern const char *names_product(u_int16_t vendorid, u_int16_t productid);
-extern const char *names_class(u_int8_t classid);
-extern const char *names_subclass(u_int8_t classid, u_int8_t subclassid);
-extern const char *names_protocol(u_int8_t classid, u_int8_t subclassid,
-                                 u_int8_t protocolid);
-extern int  names_init(char *n);
-extern void names_free(void);
-
-#endif /* _NAMES_H */
diff --git a/drivers/staging/usbip/userspace/libsrc/sysfs_utils.c b/drivers/staging/usbip/userspace/libsrc/sysfs_utils.c
deleted file mode 100644 (file)
index 36ac88e..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <errno.h>
-
-#include "sysfs_utils.h"
-#include "usbip_common.h"
-
-int write_sysfs_attribute(const char *attr_path, const char *new_value,
-                         size_t len)
-{
-       int fd;
-       int length;
-
-       fd = open(attr_path, O_WRONLY);
-       if (fd < 0) {
-               dbg("error opening attribute %s", attr_path);
-               return -1;
-       }
-
-       length = write(fd, new_value, len);
-       if (length < 0) {
-               dbg("error writing to attribute %s", attr_path);
-               close(fd);
-               return -1;
-       }
-
-       close(fd);
-
-       return 0;
-}
diff --git a/drivers/staging/usbip/userspace/libsrc/sysfs_utils.h b/drivers/staging/usbip/userspace/libsrc/sysfs_utils.h
deleted file mode 100644 (file)
index 32ac1d1..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-
-#ifndef __SYSFS_UTILS_H
-#define __SYSFS_UTILS_H
-
-int write_sysfs_attribute(const char *attr_path, const char *new_value,
-                         size_t len);
-
-#endif
diff --git a/drivers/staging/usbip/userspace/libsrc/usbip_common.c b/drivers/staging/usbip/userspace/libsrc/usbip_common.c
deleted file mode 100644 (file)
index ac73710..0000000
+++ /dev/null
@@ -1,285 +0,0 @@
-/*
- * Copyright (C) 2005-2007 Takahiro Hirofuchi
- */
-
-#include <libudev.h>
-#include "usbip_common.h"
-#include "names.h"
-
-#undef  PROGNAME
-#define PROGNAME "libusbip"
-
-int usbip_use_syslog;
-int usbip_use_stderr;
-int usbip_use_debug;
-
-extern struct udev *udev_context;
-
-struct speed_string {
-       int num;
-       char *speed;
-       char *desc;
-};
-
-static const struct speed_string speed_strings[] = {
-       { USB_SPEED_UNKNOWN, "unknown", "Unknown Speed"},
-       { USB_SPEED_LOW,  "1.5", "Low Speed(1.5Mbps)"  },
-       { USB_SPEED_FULL, "12",  "Full Speed(12Mbps)" },
-       { USB_SPEED_HIGH, "480", "High Speed(480Mbps)" },
-       { USB_SPEED_WIRELESS, "53.3-480", "Wireless"},
-       { USB_SPEED_SUPER, "5000", "Super Speed(5000Mbps)" },
-       { 0, NULL, NULL }
-};
-
-struct portst_string {
-       int num;
-       char *desc;
-};
-
-static struct portst_string portst_strings[] = {
-       { SDEV_ST_AVAILABLE,    "Device Available" },
-       { SDEV_ST_USED,         "Device in Use" },
-       { SDEV_ST_ERROR,        "Device Error"},
-       { VDEV_ST_NULL,         "Port Available"},
-       { VDEV_ST_NOTASSIGNED,  "Port Initializing"},
-       { VDEV_ST_USED,         "Port in Use"},
-       { VDEV_ST_ERROR,        "Port Error"},
-       { 0, NULL}
-};
-
-const char *usbip_status_string(int32_t status)
-{
-       for (int i = 0; portst_strings[i].desc != NULL; i++)
-               if (portst_strings[i].num == status)
-                       return portst_strings[i].desc;
-
-       return "Unknown Status";
-}
-
-const char *usbip_speed_string(int num)
-{
-       for (int i = 0; speed_strings[i].speed != NULL; i++)
-               if (speed_strings[i].num == num)
-                       return speed_strings[i].desc;
-
-       return "Unknown Speed";
-}
-
-
-#define DBG_UDEV_INTEGER(name)\
-       dbg("%-20s = %x", to_string(name), (int) udev->name)
-
-#define DBG_UINF_INTEGER(name)\
-       dbg("%-20s = %x", to_string(name), (int) uinf->name)
-
-void dump_usb_interface(struct usbip_usb_interface *uinf)
-{
-       char buff[100];
-
-       usbip_names_get_class(buff, sizeof(buff),
-                       uinf->bInterfaceClass,
-                       uinf->bInterfaceSubClass,
-                       uinf->bInterfaceProtocol);
-       dbg("%-20s = %s", "Interface(C/SC/P)", buff);
-}
-
-void dump_usb_device(struct usbip_usb_device *udev)
-{
-       char buff[100];
-
-       dbg("%-20s = %s", "path",  udev->path);
-       dbg("%-20s = %s", "busid", udev->busid);
-
-       usbip_names_get_class(buff, sizeof(buff),
-                       udev->bDeviceClass,
-                       udev->bDeviceSubClass,
-                       udev->bDeviceProtocol);
-       dbg("%-20s = %s", "Device(C/SC/P)", buff);
-
-       DBG_UDEV_INTEGER(bcdDevice);
-
-       usbip_names_get_product(buff, sizeof(buff),
-                       udev->idVendor,
-                       udev->idProduct);
-       dbg("%-20s = %s", "Vendor/Product", buff);
-
-       DBG_UDEV_INTEGER(bNumConfigurations);
-       DBG_UDEV_INTEGER(bNumInterfaces);
-
-       dbg("%-20s = %s", "speed",
-                       usbip_speed_string(udev->speed));
-
-       DBG_UDEV_INTEGER(busnum);
-       DBG_UDEV_INTEGER(devnum);
-}
-
-
-int read_attr_value(struct udev_device *dev, const char *name,
-                   const char *format)
-{
-       const char *attr;
-       int num = 0;
-       int ret;
-
-       attr = udev_device_get_sysattr_value(dev, name);
-       if (!attr) {
-               err("udev_device_get_sysattr_value failed");
-               goto err;
-       }
-
-       /* The client chooses the device configuration
-        * when attaching it so right after being bound
-        * to usbip-host on the server the device will
-        * have no configuration.
-        * Therefore, attributes such as bConfigurationValue
-        * and bNumInterfaces will not exist and sscanf will
-        * fail. Check for these cases and don't treat them
-        * as errors.
-        */
-
-       ret = sscanf(attr, format, &num);
-       if (ret < 1) {
-               if (strcmp(name, "bConfigurationValue") &&
-                               strcmp(name, "bNumInterfaces")) {
-                       err("sscanf failed for attribute %s", name);
-                       goto err;
-               }
-       }
-
-err:
-
-       return num;
-}
-
-
-int read_attr_speed(struct udev_device *dev)
-{
-       const char *speed;
-
-       speed = udev_device_get_sysattr_value(dev, "speed");
-       if (!speed) {
-               err("udev_device_get_sysattr_value failed");
-               goto err;
-       }
-
-       for (int i = 0; speed_strings[i].speed != NULL; i++) {
-               if (!strcmp(speed, speed_strings[i].speed))
-                       return speed_strings[i].num;
-       }
-
-err:
-
-       return USB_SPEED_UNKNOWN;
-}
-
-#define READ_ATTR(object, type, dev, name, format)                           \
-       do {                                                                  \
-               (object)->name = (type) read_attr_value(dev, to_string(name), \
-                                                       format);              \
-       } while (0)
-
-
-int read_usb_device(struct udev_device *sdev, struct usbip_usb_device *udev)
-{
-       uint32_t busnum, devnum;
-       const char *path, *name;
-
-       READ_ATTR(udev, uint8_t,  sdev, bDeviceClass,           "%02x\n");
-       READ_ATTR(udev, uint8_t,  sdev, bDeviceSubClass,        "%02x\n");
-       READ_ATTR(udev, uint8_t,  sdev, bDeviceProtocol,        "%02x\n");
-
-       READ_ATTR(udev, uint16_t, sdev, idVendor,               "%04x\n");
-       READ_ATTR(udev, uint16_t, sdev, idProduct,              "%04x\n");
-       READ_ATTR(udev, uint16_t, sdev, bcdDevice,              "%04x\n");
-
-       READ_ATTR(udev, uint8_t,  sdev, bConfigurationValue,    "%02x\n");
-       READ_ATTR(udev, uint8_t,  sdev, bNumConfigurations,     "%02x\n");
-       READ_ATTR(udev, uint8_t,  sdev, bNumInterfaces,         "%02x\n");
-
-       READ_ATTR(udev, uint8_t,  sdev, devnum,                 "%d\n");
-       udev->speed = read_attr_speed(sdev);
-
-       path = udev_device_get_syspath(sdev);
-       name = udev_device_get_sysname(sdev);
-
-       strncpy(udev->path,  path,  SYSFS_PATH_MAX);
-       strncpy(udev->busid, name, SYSFS_BUS_ID_SIZE);
-
-       sscanf(name, "%u-%u", &busnum, &devnum);
-       udev->busnum = busnum;
-
-       return 0;
-}
-
-int read_usb_interface(struct usbip_usb_device *udev, int i,
-                      struct usbip_usb_interface *uinf)
-{
-       char busid[SYSFS_BUS_ID_SIZE];
-       struct udev_device *sif;
-
-       sprintf(busid, "%s:%d.%d", udev->busid, udev->bConfigurationValue, i);
-
-       sif = udev_device_new_from_subsystem_sysname(udev_context, "usb", busid);
-       if (!sif) {
-               err("udev_device_new_from_subsystem_sysname %s failed", busid);
-               return -1;
-       }
-
-       READ_ATTR(uinf, uint8_t,  sif, bInterfaceClass,         "%02x\n");
-       READ_ATTR(uinf, uint8_t,  sif, bInterfaceSubClass,      "%02x\n");
-       READ_ATTR(uinf, uint8_t,  sif, bInterfaceProtocol,      "%02x\n");
-
-       return 0;
-}
-
-int usbip_names_init(char *f)
-{
-       return names_init(f);
-}
-
-void usbip_names_free(void)
-{
-       names_free();
-}
-
-void usbip_names_get_product(char *buff, size_t size, uint16_t vendor,
-                            uint16_t product)
-{
-       const char *prod, *vend;
-
-       prod = names_product(vendor, product);
-       if (!prod)
-               prod = "unknown product";
-
-
-       vend = names_vendor(vendor);
-       if (!vend)
-               vend = "unknown vendor";
-
-       snprintf(buff, size, "%s : %s (%04x:%04x)", vend, prod, vendor, product);
-}
-
-void usbip_names_get_class(char *buff, size_t size, uint8_t class,
-                          uint8_t subclass, uint8_t protocol)
-{
-       const char *c, *s, *p;
-
-       if (class == 0 && subclass == 0 && protocol == 0) {
-               snprintf(buff, size, "(Defined at Interface level) (%02x/%02x/%02x)", class, subclass, protocol);
-               return;
-       }
-
-       p = names_protocol(class, subclass, protocol);
-       if (!p)
-               p = "unknown protocol";
-
-       s = names_subclass(class, subclass);
-       if (!s)
-               s = "unknown subclass";
-
-       c = names_class(class);
-       if (!c)
-               c = "unknown class";
-
-       snprintf(buff, size, "%s / %s / %s (%02x/%02x/%02x)", c, s, p, class, subclass, protocol);
-}
diff --git a/drivers/staging/usbip/userspace/libsrc/usbip_common.h b/drivers/staging/usbip/userspace/libsrc/usbip_common.h
deleted file mode 100644 (file)
index 5a0e95e..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2005-2007 Takahiro Hirofuchi
- */
-
-#ifndef __USBIP_COMMON_H
-#define __USBIP_COMMON_H
-
-#include <libudev.h>
-
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <syslog.h>
-#include <unistd.h>
-#include <linux/usb/ch9.h>
-#include "../../uapi/usbip.h"
-
-#ifndef USBIDS_FILE
-#define USBIDS_FILE "/usr/share/hwdata/usb.ids"
-#endif
-
-#ifndef VHCI_STATE_PATH
-#define VHCI_STATE_PATH "/var/run/vhci_hcd"
-#endif
-
-/* kernel module names */
-#define USBIP_CORE_MOD_NAME    "usbip-core"
-#define USBIP_HOST_DRV_NAME    "usbip-host"
-#define USBIP_VHCI_DRV_NAME    "vhci_hcd"
-
-/* sysfs constants */
-#define SYSFS_MNT_PATH         "/sys"
-#define SYSFS_BUS_NAME         "bus"
-#define SYSFS_BUS_TYPE         "usb"
-#define SYSFS_DRIVERS_NAME     "drivers"
-
-#define SYSFS_PATH_MAX         256
-#define SYSFS_BUS_ID_SIZE      32
-
-extern int usbip_use_syslog;
-extern int usbip_use_stderr;
-extern int usbip_use_debug ;
-
-#define PROGNAME "usbip"
-
-#define pr_fmt(fmt)    "%s: %s: " fmt "\n", PROGNAME
-#define dbg_fmt(fmt)   pr_fmt("%s:%d:[%s] " fmt), "debug",     \
-                       __FILE__, __LINE__, __func__
-
-#define err(fmt, args...)                                              \
-       do {                                                            \
-               if (usbip_use_syslog) {                                 \
-                       syslog(LOG_ERR, pr_fmt(fmt), "error", ##args);  \
-               }                                                       \
-               if (usbip_use_stderr) {                                 \
-                       fprintf(stderr, pr_fmt(fmt), "error", ##args);  \
-               }                                                       \
-       } while (0)
-
-#define info(fmt, args...)                                             \
-       do {                                                            \
-               if (usbip_use_syslog) {                                 \
-                       syslog(LOG_INFO, pr_fmt(fmt), "info", ##args);  \
-               }                                                       \
-               if (usbip_use_stderr) {                                 \
-                       fprintf(stderr, pr_fmt(fmt), "info", ##args);   \
-               }                                                       \
-       } while (0)
-
-#define dbg(fmt, args...)                                              \
-       do {                                                            \
-       if (usbip_use_debug) {                                          \
-               if (usbip_use_syslog) {                                 \
-                       syslog(LOG_DEBUG, dbg_fmt(fmt), ##args);        \
-               }                                                       \
-               if (usbip_use_stderr) {                                 \
-                       fprintf(stderr, dbg_fmt(fmt), ##args);          \
-               }                                                       \
-       }                                                               \
-       } while (0)
-
-#define BUG()                                          \
-       do {                                            \
-               err("sorry, it's a bug!");              \
-               abort();                                \
-       } while (0)
-
-struct usbip_usb_interface {
-       uint8_t bInterfaceClass;
-       uint8_t bInterfaceSubClass;
-       uint8_t bInterfaceProtocol;
-       uint8_t padding;        /* alignment */
-} __attribute__((packed));
-
-struct usbip_usb_device {
-       char path[SYSFS_PATH_MAX];
-       char busid[SYSFS_BUS_ID_SIZE];
-
-       uint32_t busnum;
-       uint32_t devnum;
-       uint32_t speed;
-
-       uint16_t idVendor;
-       uint16_t idProduct;
-       uint16_t bcdDevice;
-
-       uint8_t bDeviceClass;
-       uint8_t bDeviceSubClass;
-       uint8_t bDeviceProtocol;
-       uint8_t bConfigurationValue;
-       uint8_t bNumConfigurations;
-       uint8_t bNumInterfaces;
-} __attribute__((packed));
-
-#define to_string(s)   #s
-
-void dump_usb_interface(struct usbip_usb_interface *);
-void dump_usb_device(struct usbip_usb_device *);
-int read_usb_device(struct udev_device *sdev, struct usbip_usb_device *udev);
-int read_attr_value(struct udev_device *dev, const char *name,
-                   const char *format);
-int read_usb_interface(struct usbip_usb_device *udev, int i,
-                      struct usbip_usb_interface *uinf);
-
-const char *usbip_speed_string(int num);
-const char *usbip_status_string(int32_t status);
-
-int usbip_names_init(char *);
-void usbip_names_free(void);
-void usbip_names_get_product(char *buff, size_t size, uint16_t vendor,
-                            uint16_t product);
-void usbip_names_get_class(char *buff, size_t size, uint8_t class,
-                          uint8_t subclass, uint8_t protocol);
-
-#endif /* __USBIP_COMMON_H */
diff --git a/drivers/staging/usbip/userspace/libsrc/usbip_host_driver.c b/drivers/staging/usbip/userspace/libsrc/usbip_host_driver.c
deleted file mode 100644 (file)
index bef08d5..0000000
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
- *               2005-2007 Takahiro Hirofuchi
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-#include <errno.h>
-#include <unistd.h>
-
-#include <libudev.h>
-
-#include "usbip_common.h"
-#include "usbip_host_driver.h"
-#include "list.h"
-#include "sysfs_utils.h"
-
-#undef  PROGNAME
-#define PROGNAME "libusbip"
-
-struct usbip_host_driver *host_driver;
-struct udev *udev_context;
-
-static int32_t read_attr_usbip_status(struct usbip_usb_device *udev)
-{
-       char status_attr_path[SYSFS_PATH_MAX];
-       int fd;
-       int length;
-       char status;
-       int value = 0;
-
-       snprintf(status_attr_path, SYSFS_PATH_MAX, "%s/usbip_status",
-                udev->path);
-
-       fd = open(status_attr_path, O_RDONLY);
-       if (fd < 0) {
-               err("error opening attribute %s", status_attr_path);
-               return -1;
-       }
-
-       length = read(fd, &status, 1);
-       if (length < 0) {
-               err("error reading attribute %s", status_attr_path);
-               close(fd);
-               return -1;
-       }
-
-       value = atoi(&status);
-
-       return value;
-}
-
-static
-struct usbip_exported_device *usbip_exported_device_new(const char *sdevpath)
-{
-       struct usbip_exported_device *edev = NULL;
-       struct usbip_exported_device *edev_old;
-       size_t size;
-       int i;
-
-       edev = calloc(1, sizeof(struct usbip_exported_device));
-
-       edev->sudev = udev_device_new_from_syspath(udev_context, sdevpath);
-       if (!edev->sudev) {
-               err("udev_device_new_from_syspath: %s", sdevpath);
-               goto err;
-       }
-
-       read_usb_device(edev->sudev, &edev->udev);
-
-       edev->status = read_attr_usbip_status(&edev->udev);
-       if (edev->status < 0)
-               goto err;
-
-       /* reallocate buffer to include usb interface data */
-       size = sizeof(struct usbip_exported_device) +
-               edev->udev.bNumInterfaces * sizeof(struct usbip_usb_interface);
-
-       edev_old = edev;
-       edev = realloc(edev, size);
-       if (!edev) {
-               edev = edev_old;
-               dbg("realloc failed");
-               goto err;
-       }
-
-       for (i = 0; i < edev->udev.bNumInterfaces; i++)
-               read_usb_interface(&edev->udev, i, &edev->uinf[i]);
-
-       return edev;
-err:
-       if (edev->sudev)
-               udev_device_unref(edev->sudev);
-       if (edev)
-               free(edev);
-
-       return NULL;
-}
-
-static int refresh_exported_devices(void)
-{
-       struct usbip_exported_device *edev;
-       struct udev_enumerate *enumerate;
-       struct udev_list_entry *devices, *dev_list_entry;
-       struct udev_device *dev;
-       const char *path;
-       const char *driver;
-
-       enumerate = udev_enumerate_new(udev_context);
-       udev_enumerate_add_match_subsystem(enumerate, "usb");
-       udev_enumerate_scan_devices(enumerate);
-
-       devices = udev_enumerate_get_list_entry(enumerate);
-
-       udev_list_entry_foreach(dev_list_entry, devices) {
-               path = udev_list_entry_get_name(dev_list_entry);
-               dev = udev_device_new_from_syspath(udev_context, path);
-               if (dev == NULL)
-                       continue;
-
-               /* Check whether device uses usbip-host driver. */
-               driver = udev_device_get_driver(dev);
-               if (driver != NULL && !strcmp(driver, USBIP_HOST_DRV_NAME)) {
-                       edev = usbip_exported_device_new(path);
-                       if (!edev) {
-                               dbg("usbip_exported_device_new failed");
-                               continue;
-                       }
-
-                       list_add(&edev->node, &host_driver->edev_list);
-                       host_driver->ndevs++;
-               }
-       }
-
-       return 0;
-}
-
-static void usbip_exported_device_destroy(void)
-{
-       struct list_head *i, *tmp;
-       struct usbip_exported_device *edev;
-
-       list_for_each_safe(i, tmp, &host_driver->edev_list) {
-               edev = list_entry(i, struct usbip_exported_device, node);
-               list_del(i);
-               free(edev);
-       }
-}
-
-int usbip_host_driver_open(void)
-{
-       int rc;
-
-       udev_context = udev_new();
-       if (!udev_context) {
-               err("udev_new failed");
-               return -1;
-       }
-
-       host_driver = calloc(1, sizeof(*host_driver));
-
-       host_driver->ndevs = 0;
-       INIT_LIST_HEAD(&host_driver->edev_list);
-
-       rc = refresh_exported_devices();
-       if (rc < 0)
-               goto err_free_host_driver;
-
-       return 0;
-
-err_free_host_driver:
-       free(host_driver);
-       host_driver = NULL;
-
-       udev_unref(udev_context);
-
-       return -1;
-}
-
-void usbip_host_driver_close(void)
-{
-       if (!host_driver)
-               return;
-
-       usbip_exported_device_destroy();
-
-       free(host_driver);
-       host_driver = NULL;
-
-       udev_unref(udev_context);
-}
-
-int usbip_host_refresh_device_list(void)
-{
-       int rc;
-
-       usbip_exported_device_destroy();
-
-       host_driver->ndevs = 0;
-       INIT_LIST_HEAD(&host_driver->edev_list);
-
-       rc = refresh_exported_devices();
-       if (rc < 0)
-               return -1;
-
-       return 0;
-}
-
-int usbip_host_export_device(struct usbip_exported_device *edev, int sockfd)
-{
-       char attr_name[] = "usbip_sockfd";
-       char sockfd_attr_path[SYSFS_PATH_MAX];
-       char sockfd_buff[30];
-       int ret;
-
-       if (edev->status != SDEV_ST_AVAILABLE) {
-               dbg("device not available: %s", edev->udev.busid);
-               switch (edev->status) {
-               case SDEV_ST_ERROR:
-                       dbg("status SDEV_ST_ERROR");
-                       break;
-               case SDEV_ST_USED:
-                       dbg("status SDEV_ST_USED");
-                       break;
-               default:
-                       dbg("status unknown: 0x%x", edev->status);
-               }
-               return -1;
-       }
-
-       /* only the first interface is true */
-       snprintf(sockfd_attr_path, sizeof(sockfd_attr_path), "%s/%s",
-                edev->udev.path, attr_name);
-
-       snprintf(sockfd_buff, sizeof(sockfd_buff), "%d\n", sockfd);
-
-       ret = write_sysfs_attribute(sockfd_attr_path, sockfd_buff,
-                                   strlen(sockfd_buff));
-       if (ret < 0) {
-               err("write_sysfs_attribute failed: sockfd %s to %s",
-                   sockfd_buff, sockfd_attr_path);
-               return ret;
-       }
-
-       info("connect: %s", edev->udev.busid);
-
-       return ret;
-}
-
-struct usbip_exported_device *usbip_host_get_device(int num)
-{
-       struct list_head *i;
-       struct usbip_exported_device *edev;
-       int cnt = 0;
-
-       list_for_each(i, &host_driver->edev_list) {
-               edev = list_entry(i, struct usbip_exported_device, node);
-               if (num == cnt)
-                       return edev;
-               else
-                       cnt++;
-       }
-
-       return NULL;
-}
diff --git a/drivers/staging/usbip/userspace/libsrc/usbip_host_driver.h b/drivers/staging/usbip/userspace/libsrc/usbip_host_driver.h
deleted file mode 100644 (file)
index 2a31f85..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
- *               2005-2007 Takahiro Hirofuchi
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __USBIP_HOST_DRIVER_H
-#define __USBIP_HOST_DRIVER_H
-
-#include <stdint.h>
-#include "usbip_common.h"
-#include "list.h"
-
-struct usbip_host_driver {
-       int ndevs;
-       /* list of exported device */
-       struct list_head edev_list;
-};
-
-struct usbip_exported_device {
-       struct udev_device *sudev;
-       int32_t status;
-       struct usbip_usb_device udev;
-       struct list_head node;
-       struct usbip_usb_interface uinf[];
-};
-
-extern struct usbip_host_driver *host_driver;
-
-int usbip_host_driver_open(void);
-void usbip_host_driver_close(void);
-
-int usbip_host_refresh_device_list(void);
-int usbip_host_export_device(struct usbip_exported_device *edev, int sockfd);
-struct usbip_exported_device *usbip_host_get_device(int num);
-
-#endif /* __USBIP_HOST_DRIVER_H */
diff --git a/drivers/staging/usbip/userspace/libsrc/vhci_driver.c b/drivers/staging/usbip/userspace/libsrc/vhci_driver.c
deleted file mode 100644 (file)
index ad92047..0000000
+++ /dev/null
@@ -1,411 +0,0 @@
-/*
- * Copyright (C) 2005-2007 Takahiro Hirofuchi
- */
-
-#include "usbip_common.h"
-#include "vhci_driver.h"
-#include <limits.h>
-#include <netdb.h>
-#include <libudev.h>
-#include "sysfs_utils.h"
-
-#undef  PROGNAME
-#define PROGNAME "libusbip"
-
-struct usbip_vhci_driver *vhci_driver;
-struct udev *udev_context;
-
-static struct usbip_imported_device *
-imported_device_init(struct usbip_imported_device *idev, char *busid)
-{
-       struct udev_device *sudev;
-
-       sudev = udev_device_new_from_subsystem_sysname(udev_context,
-                                                      "usb", busid);
-       if (!sudev) {
-               dbg("udev_device_new_from_subsystem_sysname failed: %s", busid);
-               goto err;
-       }
-       read_usb_device(sudev, &idev->udev);
-       udev_device_unref(sudev);
-
-       return idev;
-
-err:
-       return NULL;
-}
-
-
-
-static int parse_status(const char *value)
-{
-       int ret = 0;
-       char *c;
-
-
-       for (int i = 0; i < vhci_driver->nports; i++)
-               memset(&vhci_driver->idev[i], 0, sizeof(vhci_driver->idev[i]));
-
-
-       /* skip a header line */
-       c = strchr(value, '\n');
-       if (!c)
-               return -1;
-       c++;
-
-       while (*c != '\0') {
-               int port, status, speed, devid;
-               unsigned long socket;
-               char lbusid[SYSFS_BUS_ID_SIZE];
-
-               ret = sscanf(c, "%d %d %d %x %lx %31s\n",
-                               &port, &status, &speed,
-                               &devid, &socket, lbusid);
-
-               if (ret < 5) {
-                       dbg("sscanf failed: %d", ret);
-                       BUG();
-               }
-
-               dbg("port %d status %d speed %d devid %x",
-                               port, status, speed, devid);
-               dbg("socket %lx lbusid %s", socket, lbusid);
-
-
-               /* if a device is connected, look at it */
-               {
-                       struct usbip_imported_device *idev = &vhci_driver->idev[port];
-
-                       idev->port      = port;
-                       idev->status    = status;
-
-                       idev->devid     = devid;
-
-                       idev->busnum    = (devid >> 16);
-                       idev->devnum    = (devid & 0x0000ffff);
-
-                       if (idev->status != VDEV_ST_NULL
-                           && idev->status != VDEV_ST_NOTASSIGNED) {
-                               idev = imported_device_init(idev, lbusid);
-                               if (!idev) {
-                                       dbg("imported_device_init failed");
-                                       return -1;
-                               }
-                       }
-               }
-
-
-               /* go to the next line */
-               c = strchr(c, '\n');
-               if (!c)
-                       break;
-               c++;
-       }
-
-       dbg("exit");
-
-       return 0;
-}
-
-static int refresh_imported_device_list(void)
-{
-       const char *attr_status;
-
-       attr_status = udev_device_get_sysattr_value(vhci_driver->hc_device,
-                                              "status");
-       if (!attr_status) {
-               err("udev_device_get_sysattr_value failed");
-               return -1;
-       }
-
-       return parse_status(attr_status);
-}
-
-static int get_nports(void)
-{
-       char *c;
-       int nports = 0;
-       const char *attr_status;
-
-       attr_status = udev_device_get_sysattr_value(vhci_driver->hc_device,
-                                              "status");
-       if (!attr_status) {
-               err("udev_device_get_sysattr_value failed");
-               return -1;
-       }
-
-       /* skip a header line */
-       c = strchr(attr_status, '\n');
-       if (!c)
-               return 0;
-       c++;
-
-       while (*c != '\0') {
-               /* go to the next line */
-               c = strchr(c, '\n');
-               if (!c)
-                       return nports;
-               c++;
-               nports += 1;
-       }
-
-       return nports;
-}
-
-/*
- * Read the given port's record.
- *
- * To avoid buffer overflow we will read the entire line and
- * validate each part's size. The initial buffer is padded by 4 to
- * accommodate the 2 spaces, 1 newline and an additional character
- * which is needed to properly validate the 3rd part without it being
- * truncated to an acceptable length.
- */
-static int read_record(int rhport, char *host, unsigned long host_len,
-               char *port, unsigned long port_len, char *busid)
-{
-       int part;
-       FILE *file;
-       char path[PATH_MAX+1];
-       char *buffer, *start, *end;
-       char delim[] = {' ', ' ', '\n'};
-       int max_len[] = {(int)host_len, (int)port_len, SYSFS_BUS_ID_SIZE};
-       size_t buffer_len = host_len + port_len + SYSFS_BUS_ID_SIZE + 4;
-
-       buffer = malloc(buffer_len);
-       if (!buffer)
-               return -1;
-
-       snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport);
-
-       file = fopen(path, "r");
-       if (!file) {
-               err("fopen");
-               free(buffer);
-               return -1;
-       }
-
-       if (fgets(buffer, buffer_len, file) == NULL) {
-               err("fgets");
-               free(buffer);
-               fclose(file);
-               return -1;
-       }
-       fclose(file);
-
-       /* validate the length of each of the 3 parts */
-       start = buffer;
-       for (part = 0; part < 3; part++) {
-               end = strchr(start, delim[part]);
-               if (end == NULL || (end - start) > max_len[part]) {
-                       free(buffer);
-                       return -1;
-               }
-               start = end + 1;
-       }
-
-       if (sscanf(buffer, "%s %s %s\n", host, port, busid) != 3) {
-               err("sscanf");
-               free(buffer);
-               return -1;
-       }
-
-       free(buffer);
-
-       return 0;
-}
-
-/* ---------------------------------------------------------------------- */
-
-int usbip_vhci_driver_open(void)
-{
-       udev_context = udev_new();
-       if (!udev_context) {
-               err("udev_new failed");
-               return -1;
-       }
-
-       vhci_driver = calloc(1, sizeof(struct usbip_vhci_driver));
-
-       /* will be freed in usbip_driver_close() */
-       vhci_driver->hc_device =
-               udev_device_new_from_subsystem_sysname(udev_context,
-                                                      USBIP_VHCI_BUS_TYPE,
-                                                      USBIP_VHCI_DRV_NAME);
-       if (!vhci_driver->hc_device) {
-               err("udev_device_new_from_subsystem_sysname failed");
-               goto err;
-       }
-
-       vhci_driver->nports = get_nports();
-
-       dbg("available ports: %d", vhci_driver->nports);
-
-       if (refresh_imported_device_list())
-               goto err;
-
-       return 0;
-
-err:
-       udev_device_unref(vhci_driver->hc_device);
-
-       if (vhci_driver)
-               free(vhci_driver);
-
-       vhci_driver = NULL;
-
-       udev_unref(udev_context);
-
-       return -1;
-}
-
-
-void usbip_vhci_driver_close(void)
-{
-       if (!vhci_driver)
-               return;
-
-       udev_device_unref(vhci_driver->hc_device);
-
-       free(vhci_driver);
-
-       vhci_driver = NULL;
-
-       udev_unref(udev_context);
-}
-
-
-int usbip_vhci_refresh_device_list(void)
-{
-
-       if (refresh_imported_device_list())
-               goto err;
-
-       return 0;
-err:
-       dbg("failed to refresh device list");
-       return -1;
-}
-
-
-int usbip_vhci_get_free_port(void)
-{
-       for (int i = 0; i < vhci_driver->nports; i++) {
-               if (vhci_driver->idev[i].status == VDEV_ST_NULL)
-                       return i;
-       }
-
-       return -1;
-}
-
-int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid,
-               uint32_t speed) {
-       char buff[200]; /* what size should be ? */
-       char attach_attr_path[SYSFS_PATH_MAX];
-       char attr_attach[] = "attach";
-       const char *path;
-       int ret;
-
-       snprintf(buff, sizeof(buff), "%u %d %u %u",
-                       port, sockfd, devid, speed);
-       dbg("writing: %s", buff);
-
-       path = udev_device_get_syspath(vhci_driver->hc_device);
-       snprintf(attach_attr_path, sizeof(attach_attr_path), "%s/%s",
-                path, attr_attach);
-       dbg("attach attribute path: %s", attach_attr_path);
-
-       ret = write_sysfs_attribute(attach_attr_path, buff, strlen(buff));
-       if (ret < 0) {
-               dbg("write_sysfs_attribute failed");
-               return -1;
-       }
-
-       dbg("attached port: %d", port);
-
-       return 0;
-}
-
-static unsigned long get_devid(uint8_t busnum, uint8_t devnum)
-{
-       return (busnum << 16) | devnum;
-}
-
-/* will be removed */
-int usbip_vhci_attach_device(uint8_t port, int sockfd, uint8_t busnum,
-               uint8_t devnum, uint32_t speed)
-{
-       int devid = get_devid(busnum, devnum);
-
-       return usbip_vhci_attach_device2(port, sockfd, devid, speed);
-}
-
-int usbip_vhci_detach_device(uint8_t port)
-{
-       char detach_attr_path[SYSFS_PATH_MAX];
-       char attr_detach[] = "detach";
-       char buff[200]; /* what size should be ? */
-       const char *path;
-       int ret;
-
-       snprintf(buff, sizeof(buff), "%u", port);
-       dbg("writing: %s", buff);
-
-       path = udev_device_get_syspath(vhci_driver->hc_device);
-       snprintf(detach_attr_path, sizeof(detach_attr_path), "%s/%s",
-                path, attr_detach);
-       dbg("detach attribute path: %s", detach_attr_path);
-
-       ret = write_sysfs_attribute(detach_attr_path, buff, strlen(buff));
-       if (ret < 0) {
-               dbg("write_sysfs_attribute failed");
-               return -1;
-       }
-
-       dbg("detached port: %d", port);
-
-       return 0;
-}
-
-int usbip_vhci_imported_device_dump(struct usbip_imported_device *idev)
-{
-       char product_name[100];
-       char host[NI_MAXHOST] = "unknown host";
-       char serv[NI_MAXSERV] = "unknown port";
-       char remote_busid[SYSFS_BUS_ID_SIZE];
-       int ret;
-       int read_record_error = 0;
-
-       if (idev->status == VDEV_ST_NULL || idev->status == VDEV_ST_NOTASSIGNED)
-               return 0;
-
-       ret = read_record(idev->port, host, sizeof(host), serv, sizeof(serv),
-                         remote_busid);
-       if (ret) {
-               err("read_record");
-               read_record_error = 1;
-       }
-
-       printf("Port %02d: <%s> at %s\n", idev->port,
-              usbip_status_string(idev->status),
-              usbip_speed_string(idev->udev.speed));
-
-       usbip_names_get_product(product_name, sizeof(product_name),
-                               idev->udev.idVendor, idev->udev.idProduct);
-
-       printf("       %s\n",  product_name);
-
-       if (!read_record_error) {
-               printf("%10s -> usbip://%s:%s/%s\n", idev->udev.busid,
-                      host, serv, remote_busid);
-               printf("%10s -> remote bus/dev %03d/%03d\n", " ",
-                      idev->busnum, idev->devnum);
-       } else {
-               printf("%10s -> unknown host, remote port and remote busid\n",
-                      idev->udev.busid);
-               printf("%10s -> remote bus/dev %03d/%03d\n", " ",
-                      idev->busnum, idev->devnum);
-       }
-
-       return 0;
-}
diff --git a/drivers/staging/usbip/userspace/libsrc/vhci_driver.h b/drivers/staging/usbip/userspace/libsrc/vhci_driver.h
deleted file mode 100644 (file)
index fa2316c..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2005-2007 Takahiro Hirofuchi
- */
-
-#ifndef __VHCI_DRIVER_H
-#define __VHCI_DRIVER_H
-
-#include <libudev.h>
-#include <stdint.h>
-
-#include "usbip_common.h"
-
-#define USBIP_VHCI_BUS_TYPE "platform"
-#define MAXNPORT 128
-
-struct usbip_imported_device {
-       uint8_t port;
-       uint32_t status;
-
-       uint32_t devid;
-
-       uint8_t busnum;
-       uint8_t devnum;
-
-       /* usbip_class_device list */
-       struct usbip_usb_device udev;
-};
-
-struct usbip_vhci_driver {
-
-       /* /sys/devices/platform/vhci_hcd */
-       struct udev_device *hc_device;
-
-       int nports;
-       struct usbip_imported_device idev[MAXNPORT];
-};
-
-
-extern struct usbip_vhci_driver *vhci_driver;
-
-int usbip_vhci_driver_open(void);
-void usbip_vhci_driver_close(void);
-
-int  usbip_vhci_refresh_device_list(void);
-
-
-int usbip_vhci_get_free_port(void);
-int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid,
-               uint32_t speed);
-
-/* will be removed */
-int usbip_vhci_attach_device(uint8_t port, int sockfd, uint8_t busnum,
-               uint8_t devnum, uint32_t speed);
-
-int usbip_vhci_detach_device(uint8_t port);
-
-int usbip_vhci_imported_device_dump(struct usbip_imported_device *idev);
-
-#endif /* __VHCI_DRIVER_H */
diff --git a/drivers/staging/usbip/userspace/src/Makefile.am b/drivers/staging/usbip/userspace/src/Makefile.am
deleted file mode 100644 (file)
index e81a4eb..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-AM_CPPFLAGS = -I$(top_srcdir)/libsrc -DUSBIDS_FILE='"@USBIDS_DIR@/usb.ids"'
-AM_CFLAGS   = @EXTRA_CFLAGS@
-LDADD       = $(top_builddir)/libsrc/libusbip.la
-
-sbin_PROGRAMS := usbip usbipd
-
-usbip_SOURCES := usbip.h utils.h usbip.c utils.c usbip_network.c \
-                usbip_attach.c usbip_detach.c usbip_list.c \
-                usbip_bind.c usbip_unbind.c usbip_port.c
-
-usbipd_SOURCES := usbip_network.h usbipd.c usbip_network.c
diff --git a/drivers/staging/usbip/userspace/src/usbip.c b/drivers/staging/usbip/userspace/src/usbip.c
deleted file mode 100644 (file)
index d7599d9..0000000
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * command structure borrowed from udev
- * (git://git.kernel.org/pub/scm/linux/hotplug/udev.git)
- *
- * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
- *               2005-2007 Takahiro Hirofuchi
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <getopt.h>
-#include <syslog.h>
-
-#include "usbip_common.h"
-#include "usbip_network.h"
-#include "usbip.h"
-
-static int usbip_help(int argc, char *argv[]);
-static int usbip_version(int argc, char *argv[]);
-
-static const char usbip_version_string[] = PACKAGE_STRING;
-
-static const char usbip_usage_string[] =
-       "usbip [--debug] [--log] [--tcp-port PORT] [version]\n"
-       "             [help] <command> <args>\n";
-
-static void usbip_usage(void)
-{
-       printf("usage: %s", usbip_usage_string);
-}
-
-struct command {
-       const char *name;
-       int (*fn)(int argc, char *argv[]);
-       const char *help;
-       void (*usage)(void);
-};
-
-static const struct command cmds[] = {
-       {
-               .name  = "help",
-               .fn    = usbip_help,
-               .help  = NULL,
-               .usage = NULL
-       },
-       {
-               .name  = "version",
-               .fn    = usbip_version,
-               .help  = NULL,
-               .usage = NULL
-       },
-       {
-               .name  = "attach",
-               .fn    = usbip_attach,
-               .help  = "Attach a remote USB device",
-               .usage = usbip_attach_usage
-       },
-       {
-               .name  = "detach",
-               .fn    = usbip_detach,
-               .help  = "Detach a remote USB device",
-               .usage = usbip_detach_usage
-       },
-       {
-               .name  = "list",
-               .fn    = usbip_list,
-               .help  = "List exportable or local USB devices",
-               .usage = usbip_list_usage
-       },
-       {
-               .name  = "bind",
-               .fn    = usbip_bind,
-               .help  = "Bind device to " USBIP_HOST_DRV_NAME ".ko",
-               .usage = usbip_bind_usage
-       },
-       {
-               .name  = "unbind",
-               .fn    = usbip_unbind,
-               .help  = "Unbind device from " USBIP_HOST_DRV_NAME ".ko",
-               .usage = usbip_unbind_usage
-       },
-       {
-               .name  = "port",
-               .fn    = usbip_port_show,
-               .help  = "Show imported USB devices",
-               .usage = NULL
-       },
-       { NULL, NULL, NULL, NULL }
-};
-
-static int usbip_help(int argc, char *argv[])
-{
-       const struct command *cmd;
-       int i;
-       int ret = 0;
-
-       if (argc > 1 && argv++) {
-               for (i = 0; cmds[i].name != NULL; i++)
-                       if (!strcmp(cmds[i].name, argv[0]) && cmds[i].usage) {
-                               cmds[i].usage();
-                               goto done;
-                       }
-               ret = -1;
-       }
-
-       usbip_usage();
-       printf("\n");
-       for (cmd = cmds; cmd->name != NULL; cmd++)
-               if (cmd->help != NULL)
-                       printf("  %-10s %s\n", cmd->name, cmd->help);
-       printf("\n");
-done:
-       return ret;
-}
-
-static int usbip_version(int argc, char *argv[])
-{
-       (void) argc;
-       (void) argv;
-
-       printf(PROGNAME " (%s)\n", usbip_version_string);
-       return 0;
-}
-
-static int run_command(const struct command *cmd, int argc, char *argv[])
-{
-       dbg("running command: `%s'", cmd->name);
-       return cmd->fn(argc, argv);
-}
-
-int main(int argc, char *argv[])
-{
-       static const struct option opts[] = {
-               { "debug",    no_argument,       NULL, 'd' },
-               { "log",      no_argument,       NULL, 'l' },
-               { "tcp-port", required_argument, NULL, 't' },
-               { NULL,       0,                 NULL,  0  }
-       };
-
-       char *cmd;
-       int opt;
-       int i, rc = -1;
-
-       usbip_use_stderr = 1;
-       opterr = 0;
-       for (;;) {
-               opt = getopt_long(argc, argv, "+dlt:", opts, NULL);
-
-               if (opt == -1)
-                       break;
-
-               switch (opt) {
-               case 'd':
-                       usbip_use_debug = 1;
-                       break;
-               case 'l':
-                       usbip_use_syslog = 1;
-                       openlog("", LOG_PID, LOG_USER);
-                       break;
-               case 't':
-                       usbip_setup_port_number(optarg);
-                       break;
-               case '?':
-                       printf("usbip: invalid option\n");
-               default:
-                       usbip_usage();
-                       goto out;
-               }
-       }
-
-       cmd = argv[optind];
-       if (cmd) {
-               for (i = 0; cmds[i].name != NULL; i++)
-                       if (!strcmp(cmds[i].name, cmd)) {
-                               argc -= optind;
-                               argv += optind;
-                               optind = 0;
-                               rc = run_command(&cmds[i], argc, argv);
-                               goto out;
-                       }
-       }
-
-       /* invalid command */
-       usbip_help(0, NULL);
-out:
-       return (rc > -1 ? EXIT_SUCCESS : EXIT_FAILURE);
-}
diff --git a/drivers/staging/usbip/userspace/src/usbip.h b/drivers/staging/usbip/userspace/src/usbip.h
deleted file mode 100644 (file)
index 84fe66a..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
- *               2005-2007 Takahiro Hirofuchi
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __USBIP_H
-#define __USBIP_H
-
-#ifdef HAVE_CONFIG_H
-#include "../config.h"
-#endif
-
-/* usbip commands */
-int usbip_attach(int argc, char *argv[]);
-int usbip_detach(int argc, char *argv[]);
-int usbip_list(int argc, char *argv[]);
-int usbip_bind(int argc, char *argv[]);
-int usbip_unbind(int argc, char *argv[]);
-int usbip_port_show(int argc, char *argv[]);
-
-void usbip_attach_usage(void);
-void usbip_detach_usage(void);
-void usbip_list_usage(void);
-void usbip_bind_usage(void);
-void usbip_unbind_usage(void);
-
-#endif /* __USBIP_H */
diff --git a/drivers/staging/usbip/userspace/src/usbip_attach.c b/drivers/staging/usbip/userspace/src/usbip_attach.c
deleted file mode 100644 (file)
index d58a14d..0000000
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
- *               2005-2007 Takahiro Hirofuchi
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <sys/stat.h>
-
-#include <limits.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <fcntl.h>
-#include <getopt.h>
-#include <unistd.h>
-#include <errno.h>
-
-#include "vhci_driver.h"
-#include "usbip_common.h"
-#include "usbip_network.h"
-#include "usbip.h"
-
-static const char usbip_attach_usage_string[] =
-       "usbip attach <args>\n"
-       "    -r, --remote=<host>      The machine with exported USB devices\n"
-       "    -b, --busid=<busid>    Busid of the device on <host>\n";
-
-void usbip_attach_usage(void)
-{
-       printf("usage: %s", usbip_attach_usage_string);
-}
-
-#define MAX_BUFF 100
-static int record_connection(char *host, char *port, char *busid, int rhport)
-{
-       int fd;
-       char path[PATH_MAX+1];
-       char buff[MAX_BUFF+1];
-       int ret;
-
-       ret = mkdir(VHCI_STATE_PATH, 0700);
-       if (ret < 0) {
-               /* if VHCI_STATE_PATH exists, then it better be a directory */
-               if (errno == EEXIST) {
-                       struct stat s;
-
-                       ret = stat(VHCI_STATE_PATH, &s);
-                       if (ret < 0)
-                               return -1;
-                       if (!(s.st_mode & S_IFDIR))
-                               return -1;
-               } else
-                       return -1;
-       }
-
-       snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport);
-
-       fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU);
-       if (fd < 0)
-               return -1;
-
-       snprintf(buff, MAX_BUFF, "%s %s %s\n",
-                       host, port, busid);
-
-       ret = write(fd, buff, strlen(buff));
-       if (ret != (ssize_t) strlen(buff)) {
-               close(fd);
-               return -1;
-       }
-
-       close(fd);
-
-       return 0;
-}
-
-static int import_device(int sockfd, struct usbip_usb_device *udev)
-{
-       int rc;
-       int port;
-
-       rc = usbip_vhci_driver_open();
-       if (rc < 0) {
-               err("open vhci_driver");
-               return -1;
-       }
-
-       port = usbip_vhci_get_free_port();
-       if (port < 0) {
-               err("no free port");
-               usbip_vhci_driver_close();
-               return -1;
-       }
-
-       rc = usbip_vhci_attach_device(port, sockfd, udev->busnum,
-                                     udev->devnum, udev->speed);
-       if (rc < 0) {
-               err("import device");
-               usbip_vhci_driver_close();
-               return -1;
-       }
-
-       usbip_vhci_driver_close();
-
-       return port;
-}
-
-static int query_import_device(int sockfd, char *busid)
-{
-       int rc;
-       struct op_import_request request;
-       struct op_import_reply   reply;
-       uint16_t code = OP_REP_IMPORT;
-
-       memset(&request, 0, sizeof(request));
-       memset(&reply, 0, sizeof(reply));
-
-       /* send a request */
-       rc = usbip_net_send_op_common(sockfd, OP_REQ_IMPORT, 0);
-       if (rc < 0) {
-               err("send op_common");
-               return -1;
-       }
-
-       strncpy(request.busid, busid, SYSFS_BUS_ID_SIZE-1);
-
-       PACK_OP_IMPORT_REQUEST(0, &request);
-
-       rc = usbip_net_send(sockfd, (void *) &request, sizeof(request));
-       if (rc < 0) {
-               err("send op_import_request");
-               return -1;
-       }
-
-       /* receive a reply */
-       rc = usbip_net_recv_op_common(sockfd, &code);
-       if (rc < 0) {
-               err("recv op_common");
-               return -1;
-       }
-
-       rc = usbip_net_recv(sockfd, (void *) &reply, sizeof(reply));
-       if (rc < 0) {
-               err("recv op_import_reply");
-               return -1;
-       }
-
-       PACK_OP_IMPORT_REPLY(0, &reply);
-
-       /* check the reply */
-       if (strncmp(reply.udev.busid, busid, SYSFS_BUS_ID_SIZE)) {
-               err("recv different busid %s", reply.udev.busid);
-               return -1;
-       }
-
-       /* import a device */
-       return import_device(sockfd, &reply.udev);
-}
-
-static int attach_device(char *host, char *busid)
-{
-       int sockfd;
-       int rc;
-       int rhport;
-
-       sockfd = usbip_net_tcp_connect(host, usbip_port_string);
-       if (sockfd < 0) {
-               err("tcp connect");
-               return -1;
-       }
-
-       rhport = query_import_device(sockfd, busid);
-       if (rhport < 0) {
-               err("query");
-               return -1;
-       }
-
-       close(sockfd);
-
-       rc = record_connection(host, usbip_port_string, busid, rhport);
-       if (rc < 0) {
-               err("record connection");
-               return -1;
-       }
-
-       return 0;
-}
-
-int usbip_attach(int argc, char *argv[])
-{
-       static const struct option opts[] = {
-               { "remote", required_argument, NULL, 'r' },
-               { "busid",  required_argument, NULL, 'b' },
-               { NULL, 0,  NULL, 0 }
-       };
-       char *host = NULL;
-       char *busid = NULL;
-       int opt;
-       int ret = -1;
-
-       for (;;) {
-               opt = getopt_long(argc, argv, "r:b:", opts, NULL);
-
-               if (opt == -1)
-                       break;
-
-               switch (opt) {
-               case 'r':
-                       host = optarg;
-                       break;
-               case 'b':
-                       busid = optarg;
-                       break;
-               default:
-                       goto err_out;
-               }
-       }
-
-       if (!host || !busid)
-               goto err_out;
-
-       ret = attach_device(host, busid);
-       goto out;
-
-err_out:
-       usbip_attach_usage();
-out:
-       return ret;
-}
diff --git a/drivers/staging/usbip/userspace/src/usbip_bind.c b/drivers/staging/usbip/userspace/src/usbip_bind.c
deleted file mode 100644 (file)
index fa46141..0000000
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
- *               2005-2007 Takahiro Hirofuchi
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <libudev.h>
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <getopt.h>
-
-#include "usbip_common.h"
-#include "utils.h"
-#include "usbip.h"
-#include "sysfs_utils.h"
-
-enum unbind_status {
-       UNBIND_ST_OK,
-       UNBIND_ST_USBIP_HOST,
-       UNBIND_ST_FAILED
-};
-
-static const char usbip_bind_usage_string[] =
-       "usbip bind <args>\n"
-       "    -b, --busid=<busid>    Bind " USBIP_HOST_DRV_NAME ".ko to device "
-       "on <busid>\n";
-
-void usbip_bind_usage(void)
-{
-       printf("usage: %s", usbip_bind_usage_string);
-}
-
-/* call at unbound state */
-static int bind_usbip(char *busid)
-{
-       char attr_name[] = "bind";
-       char bind_attr_path[SYSFS_PATH_MAX];
-       int rc = -1;
-
-       snprintf(bind_attr_path, sizeof(bind_attr_path), "%s/%s/%s/%s/%s/%s",
-                SYSFS_MNT_PATH, SYSFS_BUS_NAME, SYSFS_BUS_TYPE,
-                SYSFS_DRIVERS_NAME, USBIP_HOST_DRV_NAME, attr_name);
-
-       rc = write_sysfs_attribute(bind_attr_path, busid, strlen(busid));
-       if (rc < 0) {
-               err("error binding device %s to driver: %s", busid,
-                   strerror(errno));
-               return -1;
-       }
-
-       return 0;
-}
-
-/* buggy driver may cause dead lock */
-static int unbind_other(char *busid)
-{
-       enum unbind_status status = UNBIND_ST_OK;
-
-       char attr_name[] = "unbind";
-       char unbind_attr_path[SYSFS_PATH_MAX];
-       int rc = -1;
-
-       struct udev *udev;
-       struct udev_device *dev;
-       const char *driver;
-       const char *bDevClass;
-
-       /* Create libudev context. */
-       udev = udev_new();
-
-       /* Get the device. */
-       dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid);
-       if (!dev) {
-               dbg("unable to find device with bus ID %s", busid);
-               goto err_close_busid_dev;
-       }
-
-       /* Check what kind of device it is. */
-       bDevClass  = udev_device_get_sysattr_value(dev, "bDeviceClass");
-       if (!bDevClass) {
-               dbg("unable to get bDevClass device attribute");
-               goto err_close_busid_dev;
-       }
-
-       if (!strncmp(bDevClass, "09", strlen(bDevClass))) {
-               dbg("skip unbinding of hub");
-               goto err_close_busid_dev;
-       }
-
-       /* Get the device driver. */
-       driver = udev_device_get_driver(dev);
-       if (!driver) {
-               /* No driver bound to this device. */
-               goto out;
-       }
-
-       if (!strncmp(USBIP_HOST_DRV_NAME, driver,
-                               strlen(USBIP_HOST_DRV_NAME))) {
-               /* Already bound to usbip-host. */
-               status = UNBIND_ST_USBIP_HOST;
-               goto out;
-       }
-
-       /* Unbind device from driver. */
-       snprintf(unbind_attr_path, sizeof(unbind_attr_path), "%s/%s/%s/%s/%s/%s",
-                SYSFS_MNT_PATH, SYSFS_BUS_NAME, SYSFS_BUS_TYPE,
-                SYSFS_DRIVERS_NAME, driver, attr_name);
-
-       rc = write_sysfs_attribute(unbind_attr_path, busid, strlen(busid));
-       if (rc < 0) {
-               err("error unbinding device %s from driver", busid);
-               goto err_close_busid_dev;
-       }
-
-       goto out;
-
-err_close_busid_dev:
-       status = UNBIND_ST_FAILED;
-out:
-       udev_device_unref(dev);
-       udev_unref(udev);
-
-       return status;
-}
-
-static int bind_device(char *busid)
-{
-       int rc;
-       struct udev *udev;
-       struct udev_device *dev;
-
-       /* Check whether the device with this bus ID exists. */
-       udev = udev_new();
-       dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid);
-       if (!dev) {
-               err("device with the specified bus ID does not exist");
-               return -1;
-       }
-       udev_unref(udev);
-
-       rc = unbind_other(busid);
-       if (rc == UNBIND_ST_FAILED) {
-               err("could not unbind driver from device on busid %s", busid);
-               return -1;
-       } else if (rc == UNBIND_ST_USBIP_HOST) {
-               err("device on busid %s is already bound to %s", busid,
-                   USBIP_HOST_DRV_NAME);
-               return -1;
-       }
-
-       rc = modify_match_busid(busid, 1);
-       if (rc < 0) {
-               err("unable to bind device on %s", busid);
-               return -1;
-       }
-
-       rc = bind_usbip(busid);
-       if (rc < 0) {
-               err("could not bind device to %s", USBIP_HOST_DRV_NAME);
-               modify_match_busid(busid, 0);
-               return -1;
-       }
-
-       info("bind device on busid %s: complete", busid);
-
-       return 0;
-}
-
-int usbip_bind(int argc, char *argv[])
-{
-       static const struct option opts[] = {
-               { "busid", required_argument, NULL, 'b' },
-               { NULL,    0,                 NULL,  0  }
-       };
-
-       int opt;
-       int ret = -1;
-
-       for (;;) {
-               opt = getopt_long(argc, argv, "b:", opts, NULL);
-
-               if (opt == -1)
-                       break;
-
-               switch (opt) {
-               case 'b':
-                       ret = bind_device(optarg);
-                       goto out;
-               default:
-                       goto err_out;
-               }
-       }
-
-err_out:
-       usbip_bind_usage();
-out:
-       return ret;
-}
diff --git a/drivers/staging/usbip/userspace/src/usbip_detach.c b/drivers/staging/usbip/userspace/src/usbip_detach.c
deleted file mode 100644 (file)
index 05c6d15..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
- *               2005-2007 Takahiro Hirofuchi
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <ctype.h>
-#include <limits.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <getopt.h>
-#include <unistd.h>
-
-#include "vhci_driver.h"
-#include "usbip_common.h"
-#include "usbip_network.h"
-#include "usbip.h"
-
-static const char usbip_detach_usage_string[] =
-       "usbip detach <args>\n"
-       "    -p, --port=<port>    " USBIP_VHCI_DRV_NAME
-       " port the device is on\n";
-
-void usbip_detach_usage(void)
-{
-       printf("usage: %s", usbip_detach_usage_string);
-}
-
-static int detach_port(char *port)
-{
-       int ret;
-       uint8_t portnum;
-       char path[PATH_MAX+1];
-
-       for (unsigned int i = 0; i < strlen(port); i++)
-               if (!isdigit(port[i])) {
-                       err("invalid port %s", port);
-                       return -1;
-               }
-
-       /* check max port */
-
-       portnum = atoi(port);
-
-       /* remove the port state file */
-
-       snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", portnum);
-
-       remove(path);
-       rmdir(VHCI_STATE_PATH);
-
-       ret = usbip_vhci_driver_open();
-       if (ret < 0) {
-               err("open vhci_driver");
-               return -1;
-       }
-
-       ret = usbip_vhci_detach_device(portnum);
-       if (ret < 0)
-               return -1;
-
-       usbip_vhci_driver_close();
-
-       return ret;
-}
-
-int usbip_detach(int argc, char *argv[])
-{
-       static const struct option opts[] = {
-               { "port", required_argument, NULL, 'p' },
-               { NULL, 0, NULL, 0 }
-       };
-       int opt;
-       int ret = -1;
-
-       for (;;) {
-               opt = getopt_long(argc, argv, "p:", opts, NULL);
-
-               if (opt == -1)
-                       break;
-
-               switch (opt) {
-               case 'p':
-                       ret = detach_port(optarg);
-                       goto out;
-               default:
-                       goto err_out;
-               }
-       }
-
-err_out:
-       usbip_detach_usage();
-out:
-       return ret;
-}
diff --git a/drivers/staging/usbip/userspace/src/usbip_list.c b/drivers/staging/usbip/userspace/src/usbip_list.c
deleted file mode 100644 (file)
index d5ce34a..0000000
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
- *               2005-2007 Takahiro Hirofuchi
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <sys/types.h>
-#include <libudev.h>
-
-#include <errno.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <getopt.h>
-#include <netdb.h>
-#include <unistd.h>
-
-#include "usbip_common.h"
-#include "usbip_network.h"
-#include "usbip.h"
-
-static const char usbip_list_usage_string[] =
-       "usbip list [-p|--parsable] <args>\n"
-       "    -p, --parsable         Parsable list format\n"
-       "    -r, --remote=<host>    List the exportable USB devices on <host>\n"
-       "    -l, --local            List the local USB devices\n";
-
-void usbip_list_usage(void)
-{
-       printf("usage: %s", usbip_list_usage_string);
-}
-
-static int get_exported_devices(char *host, int sockfd)
-{
-       char product_name[100];
-       char class_name[100];
-       struct op_devlist_reply reply;
-       uint16_t code = OP_REP_DEVLIST;
-       struct usbip_usb_device udev;
-       struct usbip_usb_interface uintf;
-       unsigned int i;
-       int rc, j;
-
-       rc = usbip_net_send_op_common(sockfd, OP_REQ_DEVLIST, 0);
-       if (rc < 0) {
-               dbg("usbip_net_send_op_common failed");
-               return -1;
-       }
-
-       rc = usbip_net_recv_op_common(sockfd, &code);
-       if (rc < 0) {
-               dbg("usbip_net_recv_op_common failed");
-               return -1;
-       }
-
-       memset(&reply, 0, sizeof(reply));
-       rc = usbip_net_recv(sockfd, &reply, sizeof(reply));
-       if (rc < 0) {
-               dbg("usbip_net_recv_op_devlist failed");
-               return -1;
-       }
-       PACK_OP_DEVLIST_REPLY(0, &reply);
-       dbg("exportable devices: %d\n", reply.ndev);
-
-       if (reply.ndev == 0) {
-               info("no exportable devices found on %s", host);
-               return 0;
-       }
-
-       printf("Exportable USB devices\n");
-       printf("======================\n");
-       printf(" - %s\n", host);
-
-       for (i = 0; i < reply.ndev; i++) {
-               memset(&udev, 0, sizeof(udev));
-               rc = usbip_net_recv(sockfd, &udev, sizeof(udev));
-               if (rc < 0) {
-                       dbg("usbip_net_recv failed: usbip_usb_device[%d]", i);
-                       return -1;
-               }
-               usbip_net_pack_usb_device(0, &udev);
-
-               usbip_names_get_product(product_name, sizeof(product_name),
-                                       udev.idVendor, udev.idProduct);
-               usbip_names_get_class(class_name, sizeof(class_name),
-                                     udev.bDeviceClass, udev.bDeviceSubClass,
-                                     udev.bDeviceProtocol);
-               printf("%11s: %s\n", udev.busid, product_name);
-               printf("%11s: %s\n", "", udev.path);
-               printf("%11s: %s\n", "", class_name);
-
-               for (j = 0; j < udev.bNumInterfaces; j++) {
-                       rc = usbip_net_recv(sockfd, &uintf, sizeof(uintf));
-                       if (rc < 0) {
-                               err("usbip_net_recv failed: usbip_usb_intf[%d]",
-                                               j);
-
-                               return -1;
-                       }
-                       usbip_net_pack_usb_interface(0, &uintf);
-
-                       usbip_names_get_class(class_name, sizeof(class_name),
-                                       uintf.bInterfaceClass,
-                                       uintf.bInterfaceSubClass,
-                                       uintf.bInterfaceProtocol);
-                       printf("%11s: %2d - %s\n", "", j, class_name);
-               }
-
-               printf("\n");
-       }
-
-       return 0;
-}
-
-static int list_exported_devices(char *host)
-{
-       int rc;
-       int sockfd;
-
-       sockfd = usbip_net_tcp_connect(host, usbip_port_string);
-       if (sockfd < 0) {
-               err("could not connect to %s:%s: %s", host,
-                   usbip_port_string, gai_strerror(sockfd));
-               return -1;
-       }
-       dbg("connected to %s:%s", host, usbip_port_string);
-
-       rc = get_exported_devices(host, sockfd);
-       if (rc < 0) {
-               err("failed to get device list from %s", host);
-               return -1;
-       }
-
-       close(sockfd);
-
-       return 0;
-}
-
-static void print_device(const char *busid, const char *vendor,
-                        const char *product, bool parsable)
-{
-       if (parsable)
-               printf("busid=%s#usbid=%.4s:%.4s#", busid, vendor, product);
-       else
-               printf(" - busid %s (%.4s:%.4s)\n", busid, vendor, product);
-}
-
-static void print_product_name(char *product_name, bool parsable)
-{
-       if (!parsable)
-               printf("   %s\n", product_name);
-}
-
-static int list_devices(bool parsable)
-{
-       struct udev *udev;
-       struct udev_enumerate *enumerate;
-       struct udev_list_entry *devices, *dev_list_entry;
-       struct udev_device *dev;
-       const char *path;
-       const char *idVendor;
-       const char *idProduct;
-       const char *bConfValue;
-       const char *bNumIntfs;
-       const char *busid;
-       char product_name[128];
-       int ret = -1;
-
-       /* Create libudev context. */
-       udev = udev_new();
-
-       /* Create libudev device enumeration. */
-       enumerate = udev_enumerate_new(udev);
-
-       /* Take only USB devices that are not hubs and do not have
-        * the bInterfaceNumber attribute, i.e. are not interfaces.
-        */
-       udev_enumerate_add_match_subsystem(enumerate, "usb");
-       udev_enumerate_add_nomatch_sysattr(enumerate, "bDeviceClass", "09");
-       udev_enumerate_add_nomatch_sysattr(enumerate, "bInterfaceNumber", NULL);
-       udev_enumerate_scan_devices(enumerate);
-
-       devices = udev_enumerate_get_list_entry(enumerate);
-
-       /* Show information about each device. */
-       udev_list_entry_foreach(dev_list_entry, devices) {
-               path = udev_list_entry_get_name(dev_list_entry);
-               dev = udev_device_new_from_syspath(udev, path);
-
-               /* Get device information. */
-               idVendor = udev_device_get_sysattr_value(dev, "idVendor");
-               idProduct = udev_device_get_sysattr_value(dev, "idProduct");
-               bConfValue = udev_device_get_sysattr_value(dev, "bConfigurationValue");
-               bNumIntfs = udev_device_get_sysattr_value(dev, "bNumInterfaces");
-               busid = udev_device_get_sysname(dev);
-               if (!idVendor || !idProduct || !bConfValue || !bNumIntfs) {
-                       err("problem getting device attributes: %s",
-                           strerror(errno));
-                       goto err_out;
-               }
-
-               /* Get product name. */
-               usbip_names_get_product(product_name, sizeof(product_name),
-                                       strtol(idVendor, NULL, 16),
-                                       strtol(idProduct, NULL, 16));
-
-               /* Print information. */
-               print_device(busid, idVendor, idProduct, parsable);
-               print_product_name(product_name, parsable);
-
-               printf("\n");
-
-               udev_device_unref(dev);
-       }
-
-       ret = 0;
-
-err_out:
-       udev_enumerate_unref(enumerate);
-       udev_unref(udev);
-
-       return ret;
-}
-
-int usbip_list(int argc, char *argv[])
-{
-       static const struct option opts[] = {
-               { "parsable", no_argument,       NULL, 'p' },
-               { "remote",   required_argument, NULL, 'r' },
-               { "local",    no_argument,       NULL, 'l' },
-               { NULL,       0,                 NULL,  0  }
-       };
-
-       bool parsable = false;
-       int opt;
-       int ret = -1;
-
-       if (usbip_names_init(USBIDS_FILE))
-               err("failed to open %s", USBIDS_FILE);
-
-       for (;;) {
-               opt = getopt_long(argc, argv, "pr:l", opts, NULL);
-
-               if (opt == -1)
-                       break;
-
-               switch (opt) {
-               case 'p':
-                       parsable = true;
-                       break;
-               case 'r':
-                       ret = list_exported_devices(optarg);
-                       goto out;
-               case 'l':
-                       ret = list_devices(parsable);
-                       goto out;
-               default:
-                       goto err_out;
-               }
-       }
-
-err_out:
-       usbip_list_usage();
-out:
-       usbip_names_free();
-
-       return ret;
-}
diff --git a/drivers/staging/usbip/userspace/src/usbip_network.c b/drivers/staging/usbip/userspace/src/usbip_network.c
deleted file mode 100644 (file)
index b4c37e7..0000000
+++ /dev/null
@@ -1,303 +0,0 @@
-/*
- * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
- *               2005-2007 Takahiro Hirofuchi
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <sys/socket.h>
-
-#include <string.h>
-
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <netinet/tcp.h>
-#include <unistd.h>
-
-#ifdef HAVE_LIBWRAP
-#include <tcpd.h>
-#endif
-
-#include "usbip_common.h"
-#include "usbip_network.h"
-
-int usbip_port = 3240;
-char *usbip_port_string = "3240";
-
-void usbip_setup_port_number(char *arg)
-{
-       dbg("parsing port arg '%s'", arg);
-       char *end;
-       unsigned long int port = strtoul(arg, &end, 10);
-
-       if (end == arg) {
-               err("port: could not parse '%s' as a decimal integer", arg);
-               return;
-       }
-
-       if (*end != '\0') {
-               err("port: garbage at end of '%s'", arg);
-               return;
-       }
-
-       if (port > UINT16_MAX) {
-               err("port: %s too high (max=%d)",
-                   arg, UINT16_MAX);
-               return;
-       }
-
-       usbip_port = port;
-       usbip_port_string = arg;
-       info("using port %d (\"%s\")", usbip_port, usbip_port_string);
-}
-
-void usbip_net_pack_uint32_t(int pack, uint32_t *num)
-{
-       uint32_t i;
-
-       if (pack)
-               i = htonl(*num);
-       else
-               i = ntohl(*num);
-
-       *num = i;
-}
-
-void usbip_net_pack_uint16_t(int pack, uint16_t *num)
-{
-       uint16_t i;
-
-       if (pack)
-               i = htons(*num);
-       else
-               i = ntohs(*num);
-
-       *num = i;
-}
-
-void usbip_net_pack_usb_device(int pack, struct usbip_usb_device *udev)
-{
-       usbip_net_pack_uint32_t(pack, &udev->busnum);
-       usbip_net_pack_uint32_t(pack, &udev->devnum);
-       usbip_net_pack_uint32_t(pack, &udev->speed);
-
-       usbip_net_pack_uint16_t(pack, &udev->idVendor);
-       usbip_net_pack_uint16_t(pack, &udev->idProduct);
-       usbip_net_pack_uint16_t(pack, &udev->bcdDevice);
-}
-
-void usbip_net_pack_usb_interface(int pack __attribute__((unused)),
-                                 struct usbip_usb_interface *udev
-                                 __attribute__((unused)))
-{
-       /* uint8_t members need nothing */
-}
-
-static ssize_t usbip_net_xmit(int sockfd, void *buff, size_t bufflen,
-                             int sending)
-{
-       ssize_t nbytes;
-       ssize_t total = 0;
-
-       if (!bufflen)
-               return 0;
-
-       do {
-               if (sending)
-                       nbytes = send(sockfd, buff, bufflen, 0);
-               else
-                       nbytes = recv(sockfd, buff, bufflen, MSG_WAITALL);
-
-               if (nbytes <= 0)
-                       return -1;
-
-               buff     = (void *)((intptr_t) buff + nbytes);
-               bufflen -= nbytes;
-               total   += nbytes;
-
-       } while (bufflen > 0);
-
-       return total;
-}
-
-ssize_t usbip_net_recv(int sockfd, void *buff, size_t bufflen)
-{
-       return usbip_net_xmit(sockfd, buff, bufflen, 0);
-}
-
-ssize_t usbip_net_send(int sockfd, void *buff, size_t bufflen)
-{
-       return usbip_net_xmit(sockfd, buff, bufflen, 1);
-}
-
-int usbip_net_send_op_common(int sockfd, uint32_t code, uint32_t status)
-{
-       struct op_common op_common;
-       int rc;
-
-       memset(&op_common, 0, sizeof(op_common));
-
-       op_common.version = USBIP_VERSION;
-       op_common.code    = code;
-       op_common.status  = status;
-
-       PACK_OP_COMMON(1, &op_common);
-
-       rc = usbip_net_send(sockfd, &op_common, sizeof(op_common));
-       if (rc < 0) {
-               dbg("usbip_net_send failed: %d", rc);
-               return -1;
-       }
-
-       return 0;
-}
-
-int usbip_net_recv_op_common(int sockfd, uint16_t *code)
-{
-       struct op_common op_common;
-       int rc;
-
-       memset(&op_common, 0, sizeof(op_common));
-
-       rc = usbip_net_recv(sockfd, &op_common, sizeof(op_common));
-       if (rc < 0) {
-               dbg("usbip_net_recv failed: %d", rc);
-               goto err;
-       }
-
-       PACK_OP_COMMON(0, &op_common);
-
-       if (op_common.version != USBIP_VERSION) {
-               dbg("version mismatch: %d %d", op_common.version,
-                   USBIP_VERSION);
-               goto err;
-       }
-
-       switch (*code) {
-       case OP_UNSPEC:
-               break;
-       default:
-               if (op_common.code != *code) {
-                       dbg("unexpected pdu %#0x for %#0x", op_common.code,
-                           *code);
-                       goto err;
-               }
-       }
-
-       if (op_common.status != ST_OK) {
-               dbg("request failed at peer: %d", op_common.status);
-               goto err;
-       }
-
-       *code = op_common.code;
-
-       return 0;
-err:
-       return -1;
-}
-
-int usbip_net_set_reuseaddr(int sockfd)
-{
-       const int val = 1;
-       int ret;
-
-       ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
-       if (ret < 0)
-               dbg("setsockopt: SO_REUSEADDR");
-
-       return ret;
-}
-
-int usbip_net_set_nodelay(int sockfd)
-{
-       const int val = 1;
-       int ret;
-
-       ret = setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
-       if (ret < 0)
-               dbg("setsockopt: TCP_NODELAY");
-
-       return ret;
-}
-
-int usbip_net_set_keepalive(int sockfd)
-{
-       const int val = 1;
-       int ret;
-
-       ret = setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val));
-       if (ret < 0)
-               dbg("setsockopt: SO_KEEPALIVE");
-
-       return ret;
-}
-
-int usbip_net_set_v6only(int sockfd)
-{
-       const int val = 1;
-       int ret;
-
-       ret = setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val));
-       if (ret < 0)
-               dbg("setsockopt: IPV6_V6ONLY");
-
-       return ret;
-}
-
-/*
- * IPv6 Ready
- */
-int usbip_net_tcp_connect(char *hostname, char *service)
-{
-       struct addrinfo hints, *res, *rp;
-       int sockfd;
-       int ret;
-
-       memset(&hints, 0, sizeof(hints));
-       hints.ai_family = AF_UNSPEC;
-       hints.ai_socktype = SOCK_STREAM;
-
-       /* get all possible addresses */
-       ret = getaddrinfo(hostname, service, &hints, &res);
-       if (ret < 0) {
-               dbg("getaddrinfo: %s service %s: %s", hostname, service,
-                   gai_strerror(ret));
-               return ret;
-       }
-
-       /* try the addresses */
-       for (rp = res; rp; rp = rp->ai_next) {
-               sockfd = socket(rp->ai_family, rp->ai_socktype,
-                               rp->ai_protocol);
-               if (sockfd < 0)
-                       continue;
-
-               /* should set TCP_NODELAY for usbip */
-               usbip_net_set_nodelay(sockfd);
-               /* TODO: write code for heartbeat */
-               usbip_net_set_keepalive(sockfd);
-
-               if (connect(sockfd, rp->ai_addr, rp->ai_addrlen) == 0)
-                       break;
-
-               close(sockfd);
-       }
-
-       freeaddrinfo(res);
-
-       if (!rp)
-               return EAI_SYSTEM;
-
-       return sockfd;
-}
diff --git a/drivers/staging/usbip/userspace/src/usbip_network.h b/drivers/staging/usbip/userspace/src/usbip_network.h
deleted file mode 100644 (file)
index c1e875c..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright (C) 2005-2007 Takahiro Hirofuchi
- */
-
-#ifndef __USBIP_NETWORK_H
-#define __USBIP_NETWORK_H
-
-#ifdef HAVE_CONFIG_H
-#include "../config.h"
-#endif
-
-#include <sys/types.h>
-
-#include <stdint.h>
-
-extern int usbip_port;
-extern char *usbip_port_string;
-void usbip_setup_port_number(char *arg);
-
-/* ---------------------------------------------------------------------- */
-/* Common header for all the kinds of PDUs. */
-struct op_common {
-       uint16_t version;
-
-#define OP_REQUEST     (0x80 << 8)
-#define OP_REPLY       (0x00 << 8)
-       uint16_t code;
-
-       /* add more error code */
-#define ST_OK  0x00
-#define ST_NA  0x01
-       uint32_t status; /* op_code status (for reply) */
-
-} __attribute__((packed));
-
-#define PACK_OP_COMMON(pack, op_common)  do {\
-       usbip_net_pack_uint16_t(pack, &(op_common)->version);\
-       usbip_net_pack_uint16_t(pack, &(op_common)->code);\
-       usbip_net_pack_uint32_t(pack, &(op_common)->status);\
-} while (0)
-
-/* ---------------------------------------------------------------------- */
-/* Dummy Code */
-#define OP_UNSPEC      0x00
-#define OP_REQ_UNSPEC  OP_UNSPEC
-#define OP_REP_UNSPEC  OP_UNSPEC
-
-/* ---------------------------------------------------------------------- */
-/* Retrieve USB device information. (still not used) */
-#define OP_DEVINFO     0x02
-#define OP_REQ_DEVINFO (OP_REQUEST | OP_DEVINFO)
-#define OP_REP_DEVINFO (OP_REPLY   | OP_DEVINFO)
-
-struct op_devinfo_request {
-       char busid[SYSFS_BUS_ID_SIZE];
-} __attribute__((packed));
-
-struct op_devinfo_reply {
-       struct usbip_usb_device udev;
-       struct usbip_usb_interface uinf[];
-} __attribute__((packed));
-
-/* ---------------------------------------------------------------------- */
-/* Import a remote USB device. */
-#define OP_IMPORT      0x03
-#define OP_REQ_IMPORT  (OP_REQUEST | OP_IMPORT)
-#define OP_REP_IMPORT   (OP_REPLY   | OP_IMPORT)
-
-struct op_import_request {
-       char busid[SYSFS_BUS_ID_SIZE];
-} __attribute__((packed));
-
-struct op_import_reply {
-       struct usbip_usb_device udev;
-//     struct usbip_usb_interface uinf[];
-} __attribute__((packed));
-
-#define PACK_OP_IMPORT_REQUEST(pack, request)  do {\
-} while (0)
-
-#define PACK_OP_IMPORT_REPLY(pack, reply)  do {\
-       usbip_net_pack_usb_device(pack, &(reply)->udev);\
-} while (0)
-
-/* ---------------------------------------------------------------------- */
-/* Export a USB device to a remote host. */
-#define OP_EXPORT      0x06
-#define OP_REQ_EXPORT  (OP_REQUEST | OP_EXPORT)
-#define OP_REP_EXPORT  (OP_REPLY   | OP_EXPORT)
-
-struct op_export_request {
-       struct usbip_usb_device udev;
-} __attribute__((packed));
-
-struct op_export_reply {
-       int returncode;
-} __attribute__((packed));
-
-
-#define PACK_OP_EXPORT_REQUEST(pack, request)  do {\
-       usbip_net_pack_usb_device(pack, &(request)->udev);\
-} while (0)
-
-#define PACK_OP_EXPORT_REPLY(pack, reply)  do {\
-} while (0)
-
-/* ---------------------------------------------------------------------- */
-/* un-Export a USB device from a remote host. */
-#define OP_UNEXPORT    0x07
-#define OP_REQ_UNEXPORT        (OP_REQUEST | OP_UNEXPORT)
-#define OP_REP_UNEXPORT        (OP_REPLY   | OP_UNEXPORT)
-
-struct op_unexport_request {
-       struct usbip_usb_device udev;
-} __attribute__((packed));
-
-struct op_unexport_reply {
-       int returncode;
-} __attribute__((packed));
-
-#define PACK_OP_UNEXPORT_REQUEST(pack, request)  do {\
-       usbip_net_pack_usb_device(pack, &(request)->udev);\
-} while (0)
-
-#define PACK_OP_UNEXPORT_REPLY(pack, reply)  do {\
-} while (0)
-
-/* ---------------------------------------------------------------------- */
-/* Negotiate IPSec encryption key. (still not used) */
-#define OP_CRYPKEY     0x04
-#define OP_REQ_CRYPKEY (OP_REQUEST | OP_CRYPKEY)
-#define OP_REP_CRYPKEY (OP_REPLY   | OP_CRYPKEY)
-
-struct op_crypkey_request {
-       /* 128bit key */
-       uint32_t key[4];
-} __attribute__((packed));
-
-struct op_crypkey_reply {
-       uint32_t __reserved;
-} __attribute__((packed));
-
-
-/* ---------------------------------------------------------------------- */
-/* Retrieve the list of exported USB devices. */
-#define OP_DEVLIST     0x05
-#define OP_REQ_DEVLIST (OP_REQUEST | OP_DEVLIST)
-#define OP_REP_DEVLIST (OP_REPLY   | OP_DEVLIST)
-
-struct op_devlist_request {
-} __attribute__((packed));
-
-struct op_devlist_reply {
-       uint32_t ndev;
-       /* followed by reply_extra[] */
-} __attribute__((packed));
-
-struct op_devlist_reply_extra {
-       struct usbip_usb_device    udev;
-       struct usbip_usb_interface uinf[];
-} __attribute__((packed));
-
-#define PACK_OP_DEVLIST_REQUEST(pack, request)  do {\
-} while (0)
-
-#define PACK_OP_DEVLIST_REPLY(pack, reply)  do {\
-       usbip_net_pack_uint32_t(pack, &(reply)->ndev);\
-} while (0)
-
-void usbip_net_pack_uint32_t(int pack, uint32_t *num);
-void usbip_net_pack_uint16_t(int pack, uint16_t *num);
-void usbip_net_pack_usb_device(int pack, struct usbip_usb_device *udev);
-void usbip_net_pack_usb_interface(int pack, struct usbip_usb_interface *uinf);
-
-ssize_t usbip_net_recv(int sockfd, void *buff, size_t bufflen);
-ssize_t usbip_net_send(int sockfd, void *buff, size_t bufflen);
-int usbip_net_send_op_common(int sockfd, uint32_t code, uint32_t status);
-int usbip_net_recv_op_common(int sockfd, uint16_t *code);
-int usbip_net_set_reuseaddr(int sockfd);
-int usbip_net_set_nodelay(int sockfd);
-int usbip_net_set_keepalive(int sockfd);
-int usbip_net_set_v6only(int sockfd);
-int usbip_net_tcp_connect(char *hostname, char *port);
-
-#endif /* __USBIP_NETWORK_H */
diff --git a/drivers/staging/usbip/userspace/src/usbip_port.c b/drivers/staging/usbip/userspace/src/usbip_port.c
deleted file mode 100644 (file)
index a2e884f..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
- *               2005-2007 Takahiro Hirofuchi
- *
- * 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.
- */
-
-#include "vhci_driver.h"
-#include "usbip_common.h"
-
-static int list_imported_devices(void)
-{
-       int i;
-       struct usbip_imported_device *idev;
-       int ret;
-
-       ret = usbip_vhci_driver_open();
-       if (ret < 0) {
-               err("open vhci_driver");
-               return -1;
-       }
-
-       printf("Imported USB devices\n");
-       printf("====================\n");
-
-       for (i = 0; i < vhci_driver->nports; i++) {
-               idev = &vhci_driver->idev[i];
-
-               if (usbip_vhci_imported_device_dump(idev) < 0)
-                       ret = -1;
-       }
-
-       usbip_vhci_driver_close();
-
-       return ret;
-
-}
-
-int usbip_port_show(__attribute__((unused)) int argc,
-                   __attribute__((unused)) char *argv[])
-{
-       int ret;
-
-       ret = list_imported_devices();
-       if (ret < 0)
-               err("list imported devices");
-
-       return ret;
-}
diff --git a/drivers/staging/usbip/userspace/src/usbip_unbind.c b/drivers/staging/usbip/userspace/src/usbip_unbind.c
deleted file mode 100644 (file)
index a4a496c..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
- *               2005-2007 Takahiro Hirofuchi
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <libudev.h>
-
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <getopt.h>
-
-#include "usbip_common.h"
-#include "utils.h"
-#include "usbip.h"
-#include "sysfs_utils.h"
-
-static const char usbip_unbind_usage_string[] =
-       "usbip unbind <args>\n"
-       "    -b, --busid=<busid>    Unbind " USBIP_HOST_DRV_NAME ".ko from "
-       "device on <busid>\n";
-
-void usbip_unbind_usage(void)
-{
-       printf("usage: %s", usbip_unbind_usage_string);
-}
-
-static int unbind_device(char *busid)
-{
-       char bus_type[] = "usb";
-       int rc, ret = -1;
-
-       char unbind_attr_name[] = "unbind";
-       char unbind_attr_path[SYSFS_PATH_MAX];
-       char rebind_attr_name[] = "rebind";
-       char rebind_attr_path[SYSFS_PATH_MAX];
-
-       struct udev *udev;
-       struct udev_device *dev;
-       const char *driver;
-
-       /* Create libudev context. */
-       udev = udev_new();
-
-       /* Check whether the device with this bus ID exists. */
-       dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid);
-       if (!dev) {
-               err("device with the specified bus ID does not exist");
-               goto err_close_udev;
-       }
-
-       /* Check whether the device is using usbip-host driver. */
-       driver = udev_device_get_driver(dev);
-       if (!driver || strcmp(driver, "usbip-host")) {
-               err("device is not bound to usbip-host driver");
-               goto err_close_udev;
-       }
-
-       /* Unbind device from driver. */
-       snprintf(unbind_attr_path, sizeof(unbind_attr_path), "%s/%s/%s/%s/%s/%s",
-                SYSFS_MNT_PATH, SYSFS_BUS_NAME, bus_type, SYSFS_DRIVERS_NAME,
-                USBIP_HOST_DRV_NAME, unbind_attr_name);
-
-       rc = write_sysfs_attribute(unbind_attr_path, busid, strlen(busid));
-       if (rc < 0) {
-               err("error unbinding device %s from driver", busid);
-               goto err_close_udev;
-       }
-
-       /* Notify driver of unbind. */
-       rc = modify_match_busid(busid, 0);
-       if (rc < 0) {
-               err("unable to unbind device on %s", busid);
-               goto err_close_udev;
-       }
-
-       /* Trigger new probing. */
-       snprintf(rebind_attr_path, sizeof(unbind_attr_path), "%s/%s/%s/%s/%s/%s",
-                       SYSFS_MNT_PATH, SYSFS_BUS_NAME, bus_type, SYSFS_DRIVERS_NAME,
-                       USBIP_HOST_DRV_NAME, rebind_attr_name);
-
-       rc = write_sysfs_attribute(rebind_attr_path, busid, strlen(busid));
-       if (rc < 0) {
-               err("error rebinding");
-               goto err_close_udev;
-       }
-
-       ret = 0;
-       info("unbind device on busid %s: complete", busid);
-
-err_close_udev:
-       udev_device_unref(dev);
-       udev_unref(udev);
-
-       return ret;
-}
-
-int usbip_unbind(int argc, char *argv[])
-{
-       static const struct option opts[] = {
-               { "busid", required_argument, NULL, 'b' },
-               { NULL,    0,                 NULL,  0  }
-       };
-
-       int opt;
-       int ret = -1;
-
-       for (;;) {
-               opt = getopt_long(argc, argv, "b:", opts, NULL);
-
-               if (opt == -1)
-                       break;
-
-               switch (opt) {
-               case 'b':
-                       ret = unbind_device(optarg);
-                       goto out;
-               default:
-                       goto err_out;
-               }
-       }
-
-err_out:
-       usbip_unbind_usage();
-out:
-       return ret;
-}
diff --git a/drivers/staging/usbip/userspace/src/usbipd.c b/drivers/staging/usbip/userspace/src/usbipd.c
deleted file mode 100644 (file)
index 2f87f2d..0000000
+++ /dev/null
@@ -1,679 +0,0 @@
-/*
- * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
- *               2005-2007 Takahiro Hirofuchi
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "../config.h"
-#endif
-
-#define _GNU_SOURCE
-#include <errno.h>
-#include <unistd.h>
-#include <netdb.h>
-#include <string.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <arpa/inet.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-
-#ifdef HAVE_LIBWRAP
-#include <tcpd.h>
-#endif
-
-#include <getopt.h>
-#include <signal.h>
-#include <poll.h>
-
-#include "usbip_host_driver.h"
-#include "usbip_common.h"
-#include "usbip_network.h"
-#include "list.h"
-
-#undef  PROGNAME
-#define PROGNAME "usbipd"
-#define MAXSOCKFD 20
-
-#define MAIN_LOOP_TIMEOUT 10
-
-#define DEFAULT_PID_FILE "/var/run/" PROGNAME ".pid"
-
-static const char usbip_version_string[] = PACKAGE_STRING;
-
-static const char usbipd_help_string[] =
-       "usage: usbipd [options]\n"
-       "\n"
-       "       -4, --ipv4\n"
-       "               Bind to IPv4. Default is both.\n"
-       "\n"
-       "       -6, --ipv6\n"
-       "               Bind to IPv6. Default is both.\n"
-       "\n"
-       "       -D, --daemon\n"
-       "               Run as a daemon process.\n"
-       "\n"
-       "       -d, --debug\n"
-       "               Print debugging information.\n"
-       "\n"
-       "       -PFILE, --pid FILE\n"
-       "               Write process id to FILE.\n"
-       "               If no FILE specified, use " DEFAULT_PID_FILE "\n"
-       "\n"
-       "       -tPORT, --tcp-port PORT\n"
-       "               Listen on TCP/IP port PORT.\n"
-       "\n"
-       "       -h, --help\n"
-       "               Print this help.\n"
-       "\n"
-       "       -v, --version\n"
-       "               Show version.\n";
-
-static void usbipd_help(void)
-{
-       printf("%s\n", usbipd_help_string);
-}
-
-static int recv_request_import(int sockfd)
-{
-       struct op_import_request req;
-       struct op_common reply;
-       struct usbip_exported_device *edev;
-       struct usbip_usb_device pdu_udev;
-       struct list_head *i;
-       int found = 0;
-       int error = 0;
-       int rc;
-
-       memset(&req, 0, sizeof(req));
-       memset(&reply, 0, sizeof(reply));
-
-       rc = usbip_net_recv(sockfd, &req, sizeof(req));
-       if (rc < 0) {
-               dbg("usbip_net_recv failed: import request");
-               return -1;
-       }
-       PACK_OP_IMPORT_REQUEST(0, &req);
-
-       list_for_each(i, &host_driver->edev_list) {
-               edev = list_entry(i, struct usbip_exported_device, node);
-               if (!strncmp(req.busid, edev->udev.busid, SYSFS_BUS_ID_SIZE)) {
-                       info("found requested device: %s", req.busid);
-                       found = 1;
-                       break;
-               }
-       }
-
-       if (found) {
-               /* should set TCP_NODELAY for usbip */
-               usbip_net_set_nodelay(sockfd);
-
-               /* export device needs a TCP/IP socket descriptor */
-               rc = usbip_host_export_device(edev, sockfd);
-               if (rc < 0)
-                       error = 1;
-       } else {
-               info("requested device not found: %s", req.busid);
-               error = 1;
-       }
-
-       rc = usbip_net_send_op_common(sockfd, OP_REP_IMPORT,
-                                     (!error ? ST_OK : ST_NA));
-       if (rc < 0) {
-               dbg("usbip_net_send_op_common failed: %#0x", OP_REP_IMPORT);
-               return -1;
-       }
-
-       if (error) {
-               dbg("import request busid %s: failed", req.busid);
-               return -1;
-       }
-
-       memcpy(&pdu_udev, &edev->udev, sizeof(pdu_udev));
-       usbip_net_pack_usb_device(1, &pdu_udev);
-
-       rc = usbip_net_send(sockfd, &pdu_udev, sizeof(pdu_udev));
-       if (rc < 0) {
-               dbg("usbip_net_send failed: devinfo");
-               return -1;
-       }
-
-       dbg("import request busid %s: complete", req.busid);
-
-       return 0;
-}
-
-static int send_reply_devlist(int connfd)
-{
-       struct usbip_exported_device *edev;
-       struct usbip_usb_device pdu_udev;
-       struct usbip_usb_interface pdu_uinf;
-       struct op_devlist_reply reply;
-       struct list_head *j;
-       int rc, i;
-
-       reply.ndev = 0;
-       /* number of exported devices */
-       list_for_each(j, &host_driver->edev_list) {
-               reply.ndev += 1;
-       }
-       info("exportable devices: %d", reply.ndev);
-
-       rc = usbip_net_send_op_common(connfd, OP_REP_DEVLIST, ST_OK);
-       if (rc < 0) {
-               dbg("usbip_net_send_op_common failed: %#0x", OP_REP_DEVLIST);
-               return -1;
-       }
-       PACK_OP_DEVLIST_REPLY(1, &reply);
-
-       rc = usbip_net_send(connfd, &reply, sizeof(reply));
-       if (rc < 0) {
-               dbg("usbip_net_send failed: %#0x", OP_REP_DEVLIST);
-               return -1;
-       }
-
-       list_for_each(j, &host_driver->edev_list) {
-               edev = list_entry(j, struct usbip_exported_device, node);
-               dump_usb_device(&edev->udev);
-               memcpy(&pdu_udev, &edev->udev, sizeof(pdu_udev));
-               usbip_net_pack_usb_device(1, &pdu_udev);
-
-               rc = usbip_net_send(connfd, &pdu_udev, sizeof(pdu_udev));
-               if (rc < 0) {
-                       dbg("usbip_net_send failed: pdu_udev");
-                       return -1;
-               }
-
-               for (i = 0; i < edev->udev.bNumInterfaces; i++) {
-                       dump_usb_interface(&edev->uinf[i]);
-                       memcpy(&pdu_uinf, &edev->uinf[i], sizeof(pdu_uinf));
-                       usbip_net_pack_usb_interface(1, &pdu_uinf);
-
-                       rc = usbip_net_send(connfd, &pdu_uinf,
-                                       sizeof(pdu_uinf));
-                       if (rc < 0) {
-                               err("usbip_net_send failed: pdu_uinf");
-                               return -1;
-                       }
-               }
-       }
-
-       return 0;
-}
-
-static int recv_request_devlist(int connfd)
-{
-       struct op_devlist_request req;
-       int rc;
-
-       memset(&req, 0, sizeof(req));
-
-       rc = usbip_net_recv(connfd, &req, sizeof(req));
-       if (rc < 0) {
-               dbg("usbip_net_recv failed: devlist request");
-               return -1;
-       }
-
-       rc = send_reply_devlist(connfd);
-       if (rc < 0) {
-               dbg("send_reply_devlist failed");
-               return -1;
-       }
-
-       return 0;
-}
-
-static int recv_pdu(int connfd)
-{
-       uint16_t code = OP_UNSPEC;
-       int ret;
-
-       ret = usbip_net_recv_op_common(connfd, &code);
-       if (ret < 0) {
-               dbg("could not receive opcode: %#0x", code);
-               return -1;
-       }
-
-       ret = usbip_host_refresh_device_list();
-       if (ret < 0) {
-               dbg("could not refresh device list: %d", ret);
-               return -1;
-       }
-
-       info("received request: %#0x(%d)", code, connfd);
-       switch (code) {
-       case OP_REQ_DEVLIST:
-               ret = recv_request_devlist(connfd);
-               break;
-       case OP_REQ_IMPORT:
-               ret = recv_request_import(connfd);
-               break;
-       case OP_REQ_DEVINFO:
-       case OP_REQ_CRYPKEY:
-       default:
-               err("received an unknown opcode: %#0x", code);
-               ret = -1;
-       }
-
-       if (ret == 0)
-               info("request %#0x(%d): complete", code, connfd);
-       else
-               info("request %#0x(%d): failed", code, connfd);
-
-       return ret;
-}
-
-#ifdef HAVE_LIBWRAP
-static int tcpd_auth(int connfd)
-{
-       struct request_info request;
-       int rc;
-
-       request_init(&request, RQ_DAEMON, PROGNAME, RQ_FILE, connfd, 0);
-       fromhost(&request);
-       rc = hosts_access(&request);
-       if (rc == 0)
-               return -1;
-
-       return 0;
-}
-#endif
-
-static int do_accept(int listenfd)
-{
-       int connfd;
-       struct sockaddr_storage ss;
-       socklen_t len = sizeof(ss);
-       char host[NI_MAXHOST], port[NI_MAXSERV];
-       int rc;
-
-       memset(&ss, 0, sizeof(ss));
-
-       connfd = accept(listenfd, (struct sockaddr *)&ss, &len);
-       if (connfd < 0) {
-               err("failed to accept connection");
-               return -1;
-       }
-
-       rc = getnameinfo((struct sockaddr *)&ss, len, host, sizeof(host),
-                        port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV);
-       if (rc)
-               err("getnameinfo: %s", gai_strerror(rc));
-
-#ifdef HAVE_LIBWRAP
-       rc = tcpd_auth(connfd);
-       if (rc < 0) {
-               info("denied access from %s", host);
-               close(connfd);
-               return -1;
-       }
-#endif
-       info("connection from %s:%s", host, port);
-
-       return connfd;
-}
-
-int process_request(int listenfd)
-{
-       pid_t childpid;
-       int connfd;
-
-       connfd = do_accept(listenfd);
-       if (connfd < 0)
-               return -1;
-       childpid = fork();
-       if (childpid == 0) {
-               close(listenfd);
-               recv_pdu(connfd);
-               exit(0);
-       }
-       close(connfd);
-       return 0;
-}
-
-static void addrinfo_to_text(struct addrinfo *ai, char buf[],
-                            const size_t buf_size)
-{
-       char hbuf[NI_MAXHOST];
-       char sbuf[NI_MAXSERV];
-       int rc;
-
-       buf[0] = '\0';
-
-       rc = getnameinfo(ai->ai_addr, ai->ai_addrlen, hbuf, sizeof(hbuf),
-                        sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV);
-       if (rc)
-               err("getnameinfo: %s", gai_strerror(rc));
-
-       snprintf(buf, buf_size, "%s:%s", hbuf, sbuf);
-}
-
-static int listen_all_addrinfo(struct addrinfo *ai_head, int sockfdlist[],
-                            int maxsockfd)
-{
-       struct addrinfo *ai;
-       int ret, nsockfd = 0;
-       const size_t ai_buf_size = NI_MAXHOST + NI_MAXSERV + 2;
-       char ai_buf[ai_buf_size];
-
-       for (ai = ai_head; ai && nsockfd < maxsockfd; ai = ai->ai_next) {
-               int sock;
-
-               addrinfo_to_text(ai, ai_buf, ai_buf_size);
-               dbg("opening %s", ai_buf);
-               sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
-               if (sock < 0) {
-                       err("socket: %s: %d (%s)",
-                           ai_buf, errno, strerror(errno));
-                       continue;
-               }
-
-               usbip_net_set_reuseaddr(sock);
-               usbip_net_set_nodelay(sock);
-               /* We use seperate sockets for IPv4 and IPv6
-                * (see do_standalone_mode()) */
-               usbip_net_set_v6only(sock);
-
-               if (sock >= FD_SETSIZE) {
-                       err("FD_SETSIZE: %s: sock=%d, max=%d",
-                           ai_buf, sock, FD_SETSIZE);
-                       close(sock);
-                       continue;
-               }
-
-               ret = bind(sock, ai->ai_addr, ai->ai_addrlen);
-               if (ret < 0) {
-                       err("bind: %s: %d (%s)",
-                           ai_buf, errno, strerror(errno));
-                       close(sock);
-                       continue;
-               }
-
-               ret = listen(sock, SOMAXCONN);
-               if (ret < 0) {
-                       err("listen: %s: %d (%s)",
-                           ai_buf, errno, strerror(errno));
-                       close(sock);
-                       continue;
-               }
-
-               info("listening on %s", ai_buf);
-               sockfdlist[nsockfd++] = sock;
-       }
-
-       return nsockfd;
-}
-
-static struct addrinfo *do_getaddrinfo(char *host, int ai_family)
-{
-       struct addrinfo hints, *ai_head;
-       int rc;
-
-       memset(&hints, 0, sizeof(hints));
-       hints.ai_family   = ai_family;
-       hints.ai_socktype = SOCK_STREAM;
-       hints.ai_flags    = AI_PASSIVE;
-
-       rc = getaddrinfo(host, usbip_port_string, &hints, &ai_head);
-       if (rc) {
-               err("failed to get a network address %s: %s", usbip_port_string,
-                   gai_strerror(rc));
-               return NULL;
-       }
-
-       return ai_head;
-}
-
-static void signal_handler(int i)
-{
-       dbg("received '%s' signal", strsignal(i));
-}
-
-static void set_signal(void)
-{
-       struct sigaction act;
-
-       memset(&act, 0, sizeof(act));
-       act.sa_handler = signal_handler;
-       sigemptyset(&act.sa_mask);
-       sigaction(SIGTERM, &act, NULL);
-       sigaction(SIGINT, &act, NULL);
-       act.sa_handler = SIG_IGN;
-       sigaction(SIGCLD, &act, NULL);
-}
-
-static const char *pid_file;
-
-static void write_pid_file(void)
-{
-       if (pid_file) {
-               dbg("creating pid file %s", pid_file);
-               FILE *fp;
-
-               fp = fopen(pid_file, "w");
-               if (!fp) {
-                       err("pid_file: %s: %d (%s)",
-                           pid_file, errno, strerror(errno));
-                       return;
-               }
-               fprintf(fp, "%d\n", getpid());
-               fclose(fp);
-       }
-}
-
-static void remove_pid_file(void)
-{
-       if (pid_file) {
-               dbg("removing pid file %s", pid_file);
-               unlink(pid_file);
-       }
-}
-
-static int do_standalone_mode(int daemonize, int ipv4, int ipv6)
-{
-       struct addrinfo *ai_head;
-       int sockfdlist[MAXSOCKFD];
-       int nsockfd, family;
-       int i, terminate;
-       struct pollfd *fds;
-       struct timespec timeout;
-       sigset_t sigmask;
-
-       if (usbip_host_driver_open()) {
-               err("please load " USBIP_CORE_MOD_NAME ".ko and "
-                   USBIP_HOST_DRV_NAME ".ko!");
-               return -1;
-       }
-
-       if (daemonize) {
-               if (daemon(0, 0) < 0) {
-                       err("daemonizing failed: %s", strerror(errno));
-                       usbip_host_driver_close();
-                       return -1;
-               }
-               umask(0);
-               usbip_use_syslog = 1;
-       }
-       set_signal();
-       write_pid_file();
-
-       info("starting " PROGNAME " (%s)", usbip_version_string);
-
-       /*
-        * To suppress warnings on systems with bindv6only disabled
-        * (default), we use seperate sockets for IPv6 and IPv4 and set
-        * IPV6_V6ONLY on the IPv6 sockets.
-        */
-       if (ipv4 && ipv6)
-               family = AF_UNSPEC;
-       else if (ipv4)
-               family = AF_INET;
-       else
-               family = AF_INET6;
-
-       ai_head = do_getaddrinfo(NULL, family);
-       if (!ai_head) {
-               usbip_host_driver_close();
-               return -1;
-       }
-       nsockfd = listen_all_addrinfo(ai_head, sockfdlist,
-               sizeof(sockfdlist) / sizeof(*sockfdlist));
-       freeaddrinfo(ai_head);
-       if (nsockfd <= 0) {
-               err("failed to open a listening socket");
-               usbip_host_driver_close();
-               return -1;
-       }
-
-       dbg("listening on %d address%s", nsockfd, (nsockfd == 1) ? "" : "es");
-
-       fds = calloc(nsockfd, sizeof(struct pollfd));
-       for (i = 0; i < nsockfd; i++) {
-               fds[i].fd = sockfdlist[i];
-               fds[i].events = POLLIN;
-       }
-       timeout.tv_sec = MAIN_LOOP_TIMEOUT;
-       timeout.tv_nsec = 0;
-
-       sigfillset(&sigmask);
-       sigdelset(&sigmask, SIGTERM);
-       sigdelset(&sigmask, SIGINT);
-
-       terminate = 0;
-       while (!terminate) {
-               int r;
-
-               r = ppoll(fds, nsockfd, &timeout, &sigmask);
-               if (r < 0) {
-                       dbg("%s", strerror(errno));
-                       terminate = 1;
-               } else if (r) {
-                       for (i = 0; i < nsockfd; i++) {
-                               if (fds[i].revents & POLLIN) {
-                                       dbg("read event on fd[%d]=%d",
-                                           i, sockfdlist[i]);
-                                       process_request(sockfdlist[i]);
-                               }
-                       }
-               } else {
-                       dbg("heartbeat timeout on ppoll()");
-               }
-       }
-
-       info("shutting down " PROGNAME);
-       free(fds);
-       usbip_host_driver_close();
-
-       return 0;
-}
-
-int main(int argc, char *argv[])
-{
-       static const struct option longopts[] = {
-               { "ipv4",     no_argument,       NULL, '4' },
-               { "ipv6",     no_argument,       NULL, '6' },
-               { "daemon",   no_argument,       NULL, 'D' },
-               { "daemon",   no_argument,       NULL, 'D' },
-               { "debug",    no_argument,       NULL, 'd' },
-               { "pid",      optional_argument, NULL, 'P' },
-               { "tcp-port", required_argument, NULL, 't' },
-               { "help",     no_argument,       NULL, 'h' },
-               { "version",  no_argument,       NULL, 'v' },
-               { NULL,       0,                 NULL,  0  }
-       };
-
-       enum {
-               cmd_standalone_mode = 1,
-               cmd_help,
-               cmd_version
-       } cmd;
-
-       int daemonize = 0;
-       int ipv4 = 0, ipv6 = 0;
-       int opt, rc = -1;
-
-       pid_file = NULL;
-
-       usbip_use_stderr = 1;
-       usbip_use_syslog = 0;
-
-       if (geteuid() != 0)
-               err("not running as root?");
-
-       cmd = cmd_standalone_mode;
-       for (;;) {
-               opt = getopt_long(argc, argv, "46DdP::t:hv", longopts, NULL);
-
-               if (opt == -1)
-                       break;
-
-               switch (opt) {
-               case '4':
-                       ipv4 = 1;
-                       break;
-               case '6':
-                       ipv6 = 1;
-                       break;
-               case 'D':
-                       daemonize = 1;
-                       break;
-               case 'd':
-                       usbip_use_debug = 1;
-                       break;
-               case 'h':
-                       cmd = cmd_help;
-                       break;
-               case 'P':
-                       pid_file = optarg ? optarg : DEFAULT_PID_FILE;
-                       break;
-               case 't':
-                       usbip_setup_port_number(optarg);
-                       break;
-               case 'v':
-                       cmd = cmd_version;
-                       break;
-               case '?':
-                       usbipd_help();
-               default:
-                       goto err_out;
-               }
-       }
-
-       if (!ipv4 && !ipv6)
-               ipv4 = ipv6 = 1;
-
-       switch (cmd) {
-       case cmd_standalone_mode:
-               rc = do_standalone_mode(daemonize, ipv4, ipv6);
-               remove_pid_file();
-               break;
-       case cmd_version:
-               printf(PROGNAME " (%s)\n", usbip_version_string);
-               rc = 0;
-               break;
-       case cmd_help:
-               usbipd_help();
-               rc = 0;
-               break;
-       default:
-               usbipd_help();
-               goto err_out;
-       }
-
-err_out:
-       return (rc > -1 ? EXIT_SUCCESS : EXIT_FAILURE);
-}
diff --git a/drivers/staging/usbip/userspace/src/utils.c b/drivers/staging/usbip/userspace/src/utils.c
deleted file mode 100644 (file)
index 2b3d6d2..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
- *               2005-2007 Takahiro Hirofuchi
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "usbip_common.h"
-#include "utils.h"
-#include "sysfs_utils.h"
-
-int modify_match_busid(char *busid, int add)
-{
-       char attr_name[] = "match_busid";
-       char command[SYSFS_BUS_ID_SIZE + 4];
-       char match_busid_attr_path[SYSFS_PATH_MAX];
-       int rc;
-
-       snprintf(match_busid_attr_path, sizeof(match_busid_attr_path),
-                "%s/%s/%s/%s/%s/%s", SYSFS_MNT_PATH, SYSFS_BUS_NAME,
-                SYSFS_BUS_TYPE, SYSFS_DRIVERS_NAME, USBIP_HOST_DRV_NAME,
-                attr_name);
-
-       if (add)
-               snprintf(command, SYSFS_BUS_ID_SIZE + 4, "add %s", busid);
-       else
-               snprintf(command, SYSFS_BUS_ID_SIZE + 4, "del %s", busid);
-
-       rc = write_sysfs_attribute(match_busid_attr_path, command,
-                                  sizeof(command));
-       if (rc < 0) {
-               dbg("failed to write match_busid: %s", strerror(errno));
-               return -1;
-       }
-
-       return 0;
-}
diff --git a/drivers/staging/usbip/userspace/src/utils.h b/drivers/staging/usbip/userspace/src/utils.h
deleted file mode 100644 (file)
index 5916fd3..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
- *               2005-2007 Takahiro Hirofuchi
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __UTILS_H
-#define __UTILS_H
-
-int modify_match_busid(char *busid, int add);
-
-#endif /* __UTILS_H */
-
diff --git a/drivers/staging/usbip/vhci.h b/drivers/staging/usbip/vhci.h
deleted file mode 100644 (file)
index a863a98..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2003-2008 Takahiro Hirofuchi
- *
- * This is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- */
-
-#ifndef __USBIP_VHCI_H
-#define __USBIP_VHCI_H
-
-#include <linux/device.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/sysfs.h>
-#include <linux/types.h>
-#include <linux/usb.h>
-#include <linux/usb/hcd.h>
-#include <linux/wait.h>
-
-struct vhci_device {
-       struct usb_device *udev;
-
-       /*
-        * devid specifies a remote usb device uniquely instead
-        * of combination of busnum and devnum.
-        */
-       __u32 devid;
-
-       /* speed of a remote device */
-       enum usb_device_speed speed;
-
-       /* vhci root-hub port to which this device is attached */
-       __u32 rhport;
-
-       struct usbip_device ud;
-
-       /* lock for the below link lists */
-       spinlock_t priv_lock;
-
-       /* vhci_priv is linked to one of them. */
-       struct list_head priv_tx;
-       struct list_head priv_rx;
-
-       /* vhci_unlink is linked to one of them */
-       struct list_head unlink_tx;
-       struct list_head unlink_rx;
-
-       /* vhci_tx thread sleeps for this queue */
-       wait_queue_head_t waitq_tx;
-};
-
-/* urb->hcpriv, use container_of() */
-struct vhci_priv {
-       unsigned long seqnum;
-       struct list_head list;
-
-       struct vhci_device *vdev;
-       struct urb *urb;
-};
-
-struct vhci_unlink {
-       /* seqnum of this request */
-       unsigned long seqnum;
-
-       struct list_head list;
-
-       /* seqnum of the unlink target */
-       unsigned long unlink_seqnum;
-};
-
-/* Number of supported ports. Value has an upperbound of USB_MAXCHILDREN */
-#define VHCI_NPORTS 8
-
-/* for usb_bus.hcpriv */
-struct vhci_hcd {
-       spinlock_t lock;
-
-       u32 port_status[VHCI_NPORTS];
-
-       unsigned resuming:1;
-       unsigned long re_timeout;
-
-       atomic_t seqnum;
-
-       /*
-        * NOTE:
-        * wIndex shows the port number and begins from 1.
-        * But, the index of this array begins from 0.
-        */
-       struct vhci_device vdev[VHCI_NPORTS];
-};
-
-extern struct vhci_hcd *the_controller;
-extern const struct attribute_group dev_attr_group;
-
-/* vhci_hcd.c */
-void rh_port_connect(int rhport, enum usb_device_speed speed);
-
-/* vhci_rx.c */
-struct urb *pickup_urb_and_free_priv(struct vhci_device *vdev, __u32 seqnum);
-int vhci_rx_loop(void *data);
-
-/* vhci_tx.c */
-int vhci_tx_loop(void *data);
-
-static inline struct vhci_device *port_to_vdev(__u32 port)
-{
-       return &the_controller->vdev[port];
-}
-
-static inline struct vhci_hcd *hcd_to_vhci(struct usb_hcd *hcd)
-{
-       return (struct vhci_hcd *) (hcd->hcd_priv);
-}
-
-static inline struct usb_hcd *vhci_to_hcd(struct vhci_hcd *vhci)
-{
-       return container_of((void *) vhci, struct usb_hcd, hcd_priv);
-}
-
-static inline struct device *vhci_dev(struct vhci_hcd *vhci)
-{
-       return vhci_to_hcd(vhci)->self.controller;
-}
-
-#endif /* __USBIP_VHCI_H */
diff --git a/drivers/staging/usbip/vhci_hcd.c b/drivers/staging/usbip/vhci_hcd.c
deleted file mode 100644 (file)
index c02374b..0000000
+++ /dev/null
@@ -1,1171 +0,0 @@
-/*
- * Copyright (C) 2003-2008 Takahiro Hirofuchi
- *
- * This 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 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/init.h>
-#include <linux/file.h>
-#include <linux/kernel.h>
-#include <linux/kthread.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-
-#include "usbip_common.h"
-#include "vhci.h"
-
-#define DRIVER_AUTHOR "Takahiro Hirofuchi"
-#define DRIVER_DESC "USB/IP 'Virtual' Host Controller (VHCI) Driver"
-
-/*
- * TODO
- *     - update root hub emulation
- *     - move the emulation code to userland ?
- *             porting to other operating systems
- *             minimize kernel code
- *     - add suspend/resume code
- *     - clean up everything
- */
-
-/* See usb gadget dummy hcd */
-
-static int vhci_hub_status(struct usb_hcd *hcd, char *buff);
-static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
-                           u16 wIndex, char *buff, u16 wLength);
-static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
-                           gfp_t mem_flags);
-static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status);
-static int vhci_start(struct usb_hcd *vhci_hcd);
-static void vhci_stop(struct usb_hcd *hcd);
-static int vhci_get_frame_number(struct usb_hcd *hcd);
-
-static const char driver_name[] = "vhci_hcd";
-static const char driver_desc[] = "USB/IP Virtual Host Controller";
-
-struct vhci_hcd *the_controller;
-
-static const char * const bit_desc[] = {
-       "CONNECTION",           /*0*/
-       "ENABLE",               /*1*/
-       "SUSPEND",              /*2*/
-       "OVER_CURRENT",         /*3*/
-       "RESET",                /*4*/
-       "R5",                   /*5*/
-       "R6",                   /*6*/
-       "R7",                   /*7*/
-       "POWER",                /*8*/
-       "LOWSPEED",             /*9*/
-       "HIGHSPEED",            /*10*/
-       "PORT_TEST",            /*11*/
-       "INDICATOR",            /*12*/
-       "R13",                  /*13*/
-       "R14",                  /*14*/
-       "R15",                  /*15*/
-       "C_CONNECTION",         /*16*/
-       "C_ENABLE",             /*17*/
-       "C_SUSPEND",            /*18*/
-       "C_OVER_CURRENT",       /*19*/
-       "C_RESET",              /*20*/
-       "R21",                  /*21*/
-       "R22",                  /*22*/
-       "R23",                  /*23*/
-       "R24",                  /*24*/
-       "R25",                  /*25*/
-       "R26",                  /*26*/
-       "R27",                  /*27*/
-       "R28",                  /*28*/
-       "R29",                  /*29*/
-       "R30",                  /*30*/
-       "R31",                  /*31*/
-};
-
-static void dump_port_status_diff(u32 prev_status, u32 new_status)
-{
-       int i = 0;
-       u32 bit = 1;
-
-       pr_debug("status prev -> new: %08x -> %08x\n", prev_status, new_status);
-       while (bit) {
-               u32 prev = prev_status & bit;
-               u32 new = new_status & bit;
-               char change;
-
-               if (!prev && new)
-                       change = '+';
-               else if (prev && !new)
-                       change = '-';
-               else
-                       change = ' ';
-
-               if (prev || new)
-                       pr_debug(" %c%s\n", change, bit_desc[i]);
-               bit <<= 1;
-               i++;
-       }
-       pr_debug("\n");
-}
-
-void rh_port_connect(int rhport, enum usb_device_speed speed)
-{
-       usbip_dbg_vhci_rh("rh_port_connect %d\n", rhport);
-
-       spin_lock(&the_controller->lock);
-
-       the_controller->port_status[rhport] |= USB_PORT_STAT_CONNECTION
-               | (1 << USB_PORT_FEAT_C_CONNECTION);
-
-       switch (speed) {
-       case USB_SPEED_HIGH:
-               the_controller->port_status[rhport] |= USB_PORT_STAT_HIGH_SPEED;
-               break;
-       case USB_SPEED_LOW:
-               the_controller->port_status[rhport] |= USB_PORT_STAT_LOW_SPEED;
-               break;
-       default:
-               break;
-       }
-
-       spin_unlock(&the_controller->lock);
-
-       usb_hcd_poll_rh_status(vhci_to_hcd(the_controller));
-}
-
-static void rh_port_disconnect(int rhport)
-{
-       usbip_dbg_vhci_rh("rh_port_disconnect %d\n", rhport);
-
-       spin_lock(&the_controller->lock);
-
-       the_controller->port_status[rhport] &= ~USB_PORT_STAT_CONNECTION;
-       the_controller->port_status[rhport] |=
-                                       (1 << USB_PORT_FEAT_C_CONNECTION);
-
-       spin_unlock(&the_controller->lock);
-       usb_hcd_poll_rh_status(vhci_to_hcd(the_controller));
-}
-
-#define PORT_C_MASK                            \
-       ((USB_PORT_STAT_C_CONNECTION            \
-         | USB_PORT_STAT_C_ENABLE              \
-         | USB_PORT_STAT_C_SUSPEND             \
-         | USB_PORT_STAT_C_OVERCURRENT         \
-         | USB_PORT_STAT_C_RESET) << 16)
-
-/*
- * Returns 0 if the status hasn't changed, or the number of bytes in buf.
- * Ports are 0-indexed from the HCD point of view,
- * and 1-indexed from the USB core pointer of view.
- *
- * @buf: a bitmap to show which port status has been changed.
- *  bit  0: reserved
- *  bit  1: the status of port 0 has been changed.
- *  bit  2: the status of port 1 has been changed.
- *  ...
- */
-static int vhci_hub_status(struct usb_hcd *hcd, char *buf)
-{
-       struct vhci_hcd *vhci;
-       int             retval;
-       int             rhport;
-       int             changed = 0;
-
-       retval = DIV_ROUND_UP(VHCI_NPORTS + 1, 8);
-       memset(buf, 0, retval);
-
-       vhci = hcd_to_vhci(hcd);
-
-       spin_lock(&vhci->lock);
-       if (!HCD_HW_ACCESSIBLE(hcd)) {
-               usbip_dbg_vhci_rh("hw accessible flag not on?\n");
-               goto done;
-       }
-
-       /* check pseudo status register for each port */
-       for (rhport = 0; rhport < VHCI_NPORTS; rhport++) {
-               if ((vhci->port_status[rhport] & PORT_C_MASK)) {
-                       /* The status of a port has been changed, */
-                       usbip_dbg_vhci_rh("port %d status changed\n", rhport);
-
-                       buf[(rhport + 1) / 8] |= 1 << (rhport + 1) % 8;
-                       changed = 1;
-               }
-       }
-
-       if ((hcd->state == HC_STATE_SUSPENDED) && (changed == 1))
-               usb_hcd_resume_root_hub(hcd);
-
-done:
-       spin_unlock(&vhci->lock);
-       return changed ? retval : 0;
-}
-
-static inline void hub_descriptor(struct usb_hub_descriptor *desc)
-{
-       memset(desc, 0, sizeof(*desc));
-       desc->bDescriptorType = 0x29;
-       desc->bDescLength = 9;
-       desc->wHubCharacteristics = (__constant_cpu_to_le16(0x0001));
-       desc->bNbrPorts = VHCI_NPORTS;
-       desc->u.hs.DeviceRemovable[0] = 0xff;
-       desc->u.hs.DeviceRemovable[1] = 0xff;
-}
-
-static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
-                           u16 wIndex, char *buf, u16 wLength)
-{
-       struct vhci_hcd *dum;
-       int             retval = 0;
-       int             rhport;
-
-       u32 prev_port_status[VHCI_NPORTS];
-
-       if (!HCD_HW_ACCESSIBLE(hcd))
-               return -ETIMEDOUT;
-
-       /*
-        * NOTE:
-        * wIndex shows the port number and begins from 1.
-        */
-       usbip_dbg_vhci_rh("typeReq %x wValue %x wIndex %x\n", typeReq, wValue,
-                         wIndex);
-       if (wIndex > VHCI_NPORTS)
-               pr_err("invalid port number %d\n", wIndex);
-       rhport = ((__u8)(wIndex & 0x00ff)) - 1;
-
-       dum = hcd_to_vhci(hcd);
-
-       spin_lock(&dum->lock);
-
-       /* store old status and compare now and old later */
-       if (usbip_dbg_flag_vhci_rh) {
-               memcpy(prev_port_status, dum->port_status,
-                       sizeof(prev_port_status));
-       }
-
-       switch (typeReq) {
-       case ClearHubFeature:
-               usbip_dbg_vhci_rh(" ClearHubFeature\n");
-               break;
-       case ClearPortFeature:
-               switch (wValue) {
-               case USB_PORT_FEAT_SUSPEND:
-                       if (dum->port_status[rhport] & USB_PORT_STAT_SUSPEND) {
-                               /* 20msec signaling */
-                               dum->resuming = 1;
-                               dum->re_timeout =
-                                       jiffies + msecs_to_jiffies(20);
-                       }
-                       break;
-               case USB_PORT_FEAT_POWER:
-                       usbip_dbg_vhci_rh(
-                               " ClearPortFeature: USB_PORT_FEAT_POWER\n");
-                       dum->port_status[rhport] = 0;
-                       dum->resuming = 0;
-                       break;
-               case USB_PORT_FEAT_C_RESET:
-                       usbip_dbg_vhci_rh(
-                               " ClearPortFeature: USB_PORT_FEAT_C_RESET\n");
-                       switch (dum->vdev[rhport].speed) {
-                       case USB_SPEED_HIGH:
-                               dum->port_status[rhport] |=
-                                       USB_PORT_STAT_HIGH_SPEED;
-                               break;
-                       case USB_SPEED_LOW:
-                               dum->port_status[rhport] |=
-                                       USB_PORT_STAT_LOW_SPEED;
-                               break;
-                       default:
-                               break;
-                       }
-               default:
-                       usbip_dbg_vhci_rh(" ClearPortFeature: default %x\n",
-                                         wValue);
-                       dum->port_status[rhport] &= ~(1 << wValue);
-                       break;
-               }
-               break;
-       case GetHubDescriptor:
-               usbip_dbg_vhci_rh(" GetHubDescriptor\n");
-               hub_descriptor((struct usb_hub_descriptor *) buf);
-               break;
-       case GetHubStatus:
-               usbip_dbg_vhci_rh(" GetHubStatus\n");
-               *(__le32 *) buf = cpu_to_le32(0);
-               break;
-       case GetPortStatus:
-               usbip_dbg_vhci_rh(" GetPortStatus port %x\n", wIndex);
-               if (wIndex > VHCI_NPORTS || wIndex < 1) {
-                       pr_err("invalid port number %d\n", wIndex);
-                       retval = -EPIPE;
-               }
-
-               /* we do not care about resume. */
-
-               /* whoever resets or resumes must GetPortStatus to
-                * complete it!!
-                */
-               if (dum->resuming && time_after(jiffies, dum->re_timeout)) {
-                       dum->port_status[rhport] |=
-                               (1 << USB_PORT_FEAT_C_SUSPEND);
-                       dum->port_status[rhport] &=
-                               ~(1 << USB_PORT_FEAT_SUSPEND);
-                       dum->resuming = 0;
-                       dum->re_timeout = 0;
-               }
-
-               if ((dum->port_status[rhport] & (1 << USB_PORT_FEAT_RESET)) !=
-                   0 && time_after(jiffies, dum->re_timeout)) {
-                       dum->port_status[rhport] |=
-                               (1 << USB_PORT_FEAT_C_RESET);
-                       dum->port_status[rhport] &=
-                               ~(1 << USB_PORT_FEAT_RESET);
-                       dum->re_timeout = 0;
-
-                       if (dum->vdev[rhport].ud.status ==
-                           VDEV_ST_NOTASSIGNED) {
-                               usbip_dbg_vhci_rh(
-                                       " enable rhport %d (status %u)\n",
-                                       rhport,
-                                       dum->vdev[rhport].ud.status);
-                               dum->port_status[rhport] |=
-                                       USB_PORT_STAT_ENABLE;
-                       }
-               }
-               ((__le16 *) buf)[0] = cpu_to_le16(dum->port_status[rhport]);
-               ((__le16 *) buf)[1] =
-                       cpu_to_le16(dum->port_status[rhport] >> 16);
-
-               usbip_dbg_vhci_rh(" GetPortStatus bye %x %x\n", ((u16 *)buf)[0],
-                                 ((u16 *)buf)[1]);
-               break;
-       case SetHubFeature:
-               usbip_dbg_vhci_rh(" SetHubFeature\n");
-               retval = -EPIPE;
-               break;
-       case SetPortFeature:
-               switch (wValue) {
-               case USB_PORT_FEAT_SUSPEND:
-                       usbip_dbg_vhci_rh(
-                               " SetPortFeature: USB_PORT_FEAT_SUSPEND\n");
-                       break;
-               case USB_PORT_FEAT_RESET:
-                       usbip_dbg_vhci_rh(
-                               " SetPortFeature: USB_PORT_FEAT_RESET\n");
-                       /* if it's already running, disconnect first */
-                       if (dum->port_status[rhport] & USB_PORT_STAT_ENABLE) {
-                               dum->port_status[rhport] &=
-                                       ~(USB_PORT_STAT_ENABLE |
-                                         USB_PORT_STAT_LOW_SPEED |
-                                         USB_PORT_STAT_HIGH_SPEED);
-                               /* FIXME test that code path! */
-                       }
-                       /* 50msec reset signaling */
-                       dum->re_timeout = jiffies + msecs_to_jiffies(50);
-
-                       /* FALLTHROUGH */
-               default:
-                       usbip_dbg_vhci_rh(" SetPortFeature: default %d\n",
-                                         wValue);
-                       dum->port_status[rhport] |= (1 << wValue);
-                       break;
-               }
-               break;
-
-       default:
-               pr_err("default: no such request\n");
-
-               /* "protocol stall" on error */
-               retval = -EPIPE;
-       }
-
-       if (usbip_dbg_flag_vhci_rh) {
-               pr_debug("port %d\n", rhport);
-               /* Only dump valid port status */
-               if (rhport >= 0) {
-                       dump_port_status_diff(prev_port_status[rhport],
-                                             dum->port_status[rhport]);
-               }
-       }
-       usbip_dbg_vhci_rh(" bye\n");
-
-       spin_unlock(&dum->lock);
-
-       return retval;
-}
-
-static struct vhci_device *get_vdev(struct usb_device *udev)
-{
-       int i;
-
-       if (!udev)
-               return NULL;
-
-       for (i = 0; i < VHCI_NPORTS; i++)
-               if (the_controller->vdev[i].udev == udev)
-                       return port_to_vdev(i);
-
-       return NULL;
-}
-
-static void vhci_tx_urb(struct urb *urb)
-{
-       struct vhci_device *vdev = get_vdev(urb->dev);
-       struct vhci_priv *priv;
-
-       if (!vdev) {
-               pr_err("could not get virtual device");
-               return;
-       }
-
-       priv = kzalloc(sizeof(struct vhci_priv), GFP_ATOMIC);
-       if (!priv) {
-               usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_MALLOC);
-               return;
-       }
-
-       spin_lock(&vdev->priv_lock);
-
-       priv->seqnum = atomic_inc_return(&the_controller->seqnum);
-       if (priv->seqnum == 0xffff)
-               dev_info(&urb->dev->dev, "seqnum max\n");
-
-       priv->vdev = vdev;
-       priv->urb = urb;
-
-       urb->hcpriv = (void *) priv;
-
-       list_add_tail(&priv->list, &vdev->priv_tx);
-
-       wake_up(&vdev->waitq_tx);
-       spin_unlock(&vdev->priv_lock);
-}
-
-static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
-                           gfp_t mem_flags)
-{
-       struct device *dev = &urb->dev->dev;
-       int ret = 0;
-       struct vhci_device *vdev;
-
-       usbip_dbg_vhci_hc("enter, usb_hcd %p urb %p mem_flags %d\n",
-                         hcd, urb, mem_flags);
-
-       /* patch to usb_sg_init() is in 2.5.60 */
-       BUG_ON(!urb->transfer_buffer && urb->transfer_buffer_length);
-
-       spin_lock(&the_controller->lock);
-
-       if (urb->status != -EINPROGRESS) {
-               dev_err(dev, "URB already unlinked!, status %d\n", urb->status);
-               spin_unlock(&the_controller->lock);
-               return urb->status;
-       }
-
-       vdev = port_to_vdev(urb->dev->portnum-1);
-
-       /* refuse enqueue for dead connection */
-       spin_lock(&vdev->ud.lock);
-       if (vdev->ud.status == VDEV_ST_NULL ||
-           vdev->ud.status == VDEV_ST_ERROR) {
-               dev_err(dev, "enqueue for inactive port %d\n", vdev->rhport);
-               spin_unlock(&vdev->ud.lock);
-               spin_unlock(&the_controller->lock);
-               return -ENODEV;
-       }
-       spin_unlock(&vdev->ud.lock);
-
-       ret = usb_hcd_link_urb_to_ep(hcd, urb);
-       if (ret)
-               goto no_need_unlink;
-
-       /*
-        * The enumeration process is as follows;
-        *
-        *  1. Get_Descriptor request to DevAddrs(0) EndPoint(0)
-        *     to get max packet length of default pipe
-        *
-        *  2. Set_Address request to DevAddr(0) EndPoint(0)
-        *
-        */
-       if (usb_pipedevice(urb->pipe) == 0) {
-               __u8 type = usb_pipetype(urb->pipe);
-               struct usb_ctrlrequest *ctrlreq =
-                       (struct usb_ctrlrequest *) urb->setup_packet;
-
-               if (type != PIPE_CONTROL || !ctrlreq) {
-                       dev_err(dev, "invalid request to devnum 0\n");
-                       ret = -EINVAL;
-                       goto no_need_xmit;
-               }
-
-               switch (ctrlreq->bRequest) {
-               case USB_REQ_SET_ADDRESS:
-                       /* set_address may come when a device is reset */
-                       dev_info(dev, "SetAddress Request (%d) to port %d\n",
-                                ctrlreq->wValue, vdev->rhport);
-
-                       if (vdev->udev)
-                               usb_put_dev(vdev->udev);
-                       vdev->udev = usb_get_dev(urb->dev);
-
-                       spin_lock(&vdev->ud.lock);
-                       vdev->ud.status = VDEV_ST_USED;
-                       spin_unlock(&vdev->ud.lock);
-
-                       if (urb->status == -EINPROGRESS) {
-                               /* This request is successfully completed. */
-                               /* If not -EINPROGRESS, possibly unlinked. */
-                               urb->status = 0;
-                       }
-
-                       goto no_need_xmit;
-
-               case USB_REQ_GET_DESCRIPTOR:
-                       if (ctrlreq->wValue == cpu_to_le16(USB_DT_DEVICE << 8))
-                               usbip_dbg_vhci_hc(
-                                       "Not yet?:Get_Descriptor to device 0 (get max pipe size)\n");
-
-                       if (vdev->udev)
-                               usb_put_dev(vdev->udev);
-                       vdev->udev = usb_get_dev(urb->dev);
-                       goto out;
-
-               default:
-                       /* NOT REACHED */
-                       dev_err(dev,
-                               "invalid request to devnum 0 bRequest %u, wValue %u\n",
-                               ctrlreq->bRequest,
-                               ctrlreq->wValue);
-                       ret =  -EINVAL;
-                       goto no_need_xmit;
-               }
-
-       }
-
-out:
-       vhci_tx_urb(urb);
-       spin_unlock(&the_controller->lock);
-
-       return 0;
-
-no_need_xmit:
-       usb_hcd_unlink_urb_from_ep(hcd, urb);
-no_need_unlink:
-       spin_unlock(&the_controller->lock);
-       usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, urb->status);
-       return ret;
-}
-
-/*
- * vhci_rx gives back the urb after receiving the reply of the urb.  If an
- * unlink pdu is sent or not, vhci_rx receives a normal return pdu and gives
- * back its urb. For the driver unlinking the urb, the content of the urb is
- * not important, but the calling to its completion handler is important; the
- * completion of unlinking is notified by the completion handler.
- *
- *
- * CLIENT SIDE
- *
- * - When vhci_hcd receives RET_SUBMIT,
- *
- *     - case 1a). the urb of the pdu is not unlinking.
- *             - normal case
- *             => just give back the urb
- *
- *     - case 1b). the urb of the pdu is unlinking.
- *             - usbip.ko will return a reply of the unlinking request.
- *             => give back the urb now and go to case 2b).
- *
- * - When vhci_hcd receives RET_UNLINK,
- *
- *     - case 2a). a submit request is still pending in vhci_hcd.
- *             - urb was really pending in usbip.ko and urb_unlink_urb() was
- *               completed there.
- *             => free a pending submit request
- *             => notify unlink completeness by giving back the urb
- *
- *     - case 2b). a submit request is *not* pending in vhci_hcd.
- *             - urb was already given back to the core driver.
- *             => do not give back the urb
- *
- *
- * SERVER SIDE
- *
- * - When usbip receives CMD_UNLINK,
- *
- *     - case 3a). the urb of the unlink request is now in submission.
- *             => do usb_unlink_urb().
- *             => after the unlink is completed, send RET_UNLINK.
- *
- *     - case 3b). the urb of the unlink request is not in submission.
- *             - may be already completed or never be received
- *             => send RET_UNLINK
- *
- */
-static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
-{
-       struct vhci_priv *priv;
-       struct vhci_device *vdev;
-
-       pr_info("dequeue a urb %p\n", urb);
-
-       spin_lock(&the_controller->lock);
-
-       priv = urb->hcpriv;
-       if (!priv) {
-               /* URB was never linked! or will be soon given back by
-                * vhci_rx. */
-               spin_unlock(&the_controller->lock);
-               return 0;
-       }
-
-       {
-               int ret = 0;
-
-               ret = usb_hcd_check_unlink_urb(hcd, urb, status);
-               if (ret) {
-                       spin_unlock(&the_controller->lock);
-                       return ret;
-               }
-       }
-
-        /* send unlink request here? */
-       vdev = priv->vdev;
-
-       if (!vdev->ud.tcp_socket) {
-               /* tcp connection is closed */
-               spin_lock(&vdev->priv_lock);
-
-               pr_info("device %p seems to be disconnected\n", vdev);
-               list_del(&priv->list);
-               kfree(priv);
-               urb->hcpriv = NULL;
-
-               spin_unlock(&vdev->priv_lock);
-
-               /*
-                * If tcp connection is alive, we have sent CMD_UNLINK.
-                * vhci_rx will receive RET_UNLINK and give back the URB.
-                * Otherwise, we give back it here.
-                */
-               pr_info("gives back urb %p\n", urb);
-
-               usb_hcd_unlink_urb_from_ep(hcd, urb);
-
-               spin_unlock(&the_controller->lock);
-               usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb,
-                                    urb->status);
-               spin_lock(&the_controller->lock);
-
-       } else {
-               /* tcp connection is alive */
-               struct vhci_unlink *unlink;
-
-               spin_lock(&vdev->priv_lock);
-
-               /* setup CMD_UNLINK pdu */
-               unlink = kzalloc(sizeof(struct vhci_unlink), GFP_ATOMIC);
-               if (!unlink) {
-                       spin_unlock(&vdev->priv_lock);
-                       spin_unlock(&the_controller->lock);
-                       usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_MALLOC);
-                       return -ENOMEM;
-               }
-
-               unlink->seqnum = atomic_inc_return(&the_controller->seqnum);
-               if (unlink->seqnum == 0xffff)
-                       pr_info("seqnum max\n");
-
-               unlink->unlink_seqnum = priv->seqnum;
-
-               pr_info("device %p seems to be still connected\n", vdev);
-
-               /* send cmd_unlink and try to cancel the pending URB in the
-                * peer */
-               list_add_tail(&unlink->list, &vdev->unlink_tx);
-               wake_up(&vdev->waitq_tx);
-
-               spin_unlock(&vdev->priv_lock);
-       }
-
-       spin_unlock(&the_controller->lock);
-
-       usbip_dbg_vhci_hc("leave\n");
-       return 0;
-}
-
-static void vhci_device_unlink_cleanup(struct vhci_device *vdev)
-{
-       struct vhci_unlink *unlink, *tmp;
-
-       spin_lock(&the_controller->lock);
-       spin_lock(&vdev->priv_lock);
-
-       list_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) {
-               pr_info("unlink cleanup tx %lu\n", unlink->unlink_seqnum);
-               list_del(&unlink->list);
-               kfree(unlink);
-       }
-
-       while (!list_empty(&vdev->unlink_rx)) {
-               struct urb *urb;
-
-               unlink = list_first_entry(&vdev->unlink_rx, struct vhci_unlink,
-                       list);
-
-               /* give back URB of unanswered unlink request */
-               pr_info("unlink cleanup rx %lu\n", unlink->unlink_seqnum);
-
-               urb = pickup_urb_and_free_priv(vdev, unlink->unlink_seqnum);
-               if (!urb) {
-                       pr_info("the urb (seqnum %lu) was already given back\n",
-                               unlink->unlink_seqnum);
-                       list_del(&unlink->list);
-                       kfree(unlink);
-                       continue;
-               }
-
-               urb->status = -ENODEV;
-
-               usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb);
-
-               list_del(&unlink->list);
-
-               spin_unlock(&vdev->priv_lock);
-               spin_unlock(&the_controller->lock);
-
-               usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb,
-                                    urb->status);
-
-               spin_lock(&the_controller->lock);
-               spin_lock(&vdev->priv_lock);
-
-               kfree(unlink);
-       }
-
-       spin_unlock(&vdev->priv_lock);
-       spin_unlock(&the_controller->lock);
-}
-
-/*
- * The important thing is that only one context begins cleanup.
- * This is why error handling and cleanup become simple.
- * We do not want to consider race condition as possible.
- */
-static void vhci_shutdown_connection(struct usbip_device *ud)
-{
-       struct vhci_device *vdev = container_of(ud, struct vhci_device, ud);
-
-       /* need this? see stub_dev.c */
-       if (ud->tcp_socket) {
-               pr_debug("shutdown tcp_socket %p\n", ud->tcp_socket);
-               kernel_sock_shutdown(ud->tcp_socket, SHUT_RDWR);
-       }
-
-       /* kill threads related to this sdev */
-       if (vdev->ud.tcp_rx) {
-               kthread_stop_put(vdev->ud.tcp_rx);
-               vdev->ud.tcp_rx = NULL;
-       }
-       if (vdev->ud.tcp_tx) {
-               kthread_stop_put(vdev->ud.tcp_tx);
-               vdev->ud.tcp_tx = NULL;
-       }
-       pr_info("stop threads\n");
-
-       /* active connection is closed */
-       if (vdev->ud.tcp_socket) {
-               sockfd_put(vdev->ud.tcp_socket);
-               vdev->ud.tcp_socket = NULL;
-       }
-       pr_info("release socket\n");
-
-       vhci_device_unlink_cleanup(vdev);
-
-       /*
-        * rh_port_disconnect() is a trigger of ...
-        *   usb_disable_device():
-        *      disable all the endpoints for a USB device.
-        *   usb_disable_endpoint():
-        *      disable endpoints. pending urbs are unlinked(dequeued).
-        *
-        * NOTE: After calling rh_port_disconnect(), the USB device drivers of a
-        * detached device should release used urbs in a cleanup function (i.e.
-        * xxx_disconnect()). Therefore, vhci_hcd does not need to release
-        * pushed urbs and their private data in this function.
-        *
-        * NOTE: vhci_dequeue() must be considered carefully. When shutting down
-        * a connection, vhci_shutdown_connection() expects vhci_dequeue()
-        * gives back pushed urbs and frees their private data by request of
-        * the cleanup function of a USB driver. When unlinking a urb with an
-        * active connection, vhci_dequeue() does not give back the urb which
-        * is actually given back by vhci_rx after receiving its return pdu.
-        *
-        */
-       rh_port_disconnect(vdev->rhport);
-
-       pr_info("disconnect device\n");
-}
-
-
-static void vhci_device_reset(struct usbip_device *ud)
-{
-       struct vhci_device *vdev = container_of(ud, struct vhci_device, ud);
-
-       spin_lock(&ud->lock);
-
-       vdev->speed  = 0;
-       vdev->devid  = 0;
-
-       if (vdev->udev)
-               usb_put_dev(vdev->udev);
-       vdev->udev = NULL;
-
-       if (ud->tcp_socket) {
-               sockfd_put(ud->tcp_socket);
-               ud->tcp_socket = NULL;
-       }
-       ud->status = VDEV_ST_NULL;
-
-       spin_unlock(&ud->lock);
-}
-
-static void vhci_device_unusable(struct usbip_device *ud)
-{
-       spin_lock(&ud->lock);
-       ud->status = VDEV_ST_ERROR;
-       spin_unlock(&ud->lock);
-}
-
-static void vhci_device_init(struct vhci_device *vdev)
-{
-       memset(vdev, 0, sizeof(*vdev));
-
-       vdev->ud.side   = USBIP_VHCI;
-       vdev->ud.status = VDEV_ST_NULL;
-       spin_lock_init(&vdev->ud.lock);
-
-       INIT_LIST_HEAD(&vdev->priv_rx);
-       INIT_LIST_HEAD(&vdev->priv_tx);
-       INIT_LIST_HEAD(&vdev->unlink_tx);
-       INIT_LIST_HEAD(&vdev->unlink_rx);
-       spin_lock_init(&vdev->priv_lock);
-
-       init_waitqueue_head(&vdev->waitq_tx);
-
-       vdev->ud.eh_ops.shutdown = vhci_shutdown_connection;
-       vdev->ud.eh_ops.reset = vhci_device_reset;
-       vdev->ud.eh_ops.unusable = vhci_device_unusable;
-
-       usbip_start_eh(&vdev->ud);
-}
-
-static int vhci_start(struct usb_hcd *hcd)
-{
-       struct vhci_hcd *vhci = hcd_to_vhci(hcd);
-       int rhport;
-       int err = 0;
-
-       usbip_dbg_vhci_hc("enter vhci_start\n");
-
-       /* initialize private data of usb_hcd */
-
-       for (rhport = 0; rhport < VHCI_NPORTS; rhport++) {
-               struct vhci_device *vdev = &vhci->vdev[rhport];
-
-               vhci_device_init(vdev);
-               vdev->rhport = rhport;
-       }
-
-       atomic_set(&vhci->seqnum, 0);
-       spin_lock_init(&vhci->lock);
-
-       hcd->power_budget = 0; /* no limit */
-       hcd->uses_new_polling = 1;
-
-       /* vhci_hcd is now ready to be controlled through sysfs */
-       err = sysfs_create_group(&vhci_dev(vhci)->kobj, &dev_attr_group);
-       if (err) {
-               pr_err("create sysfs files\n");
-               return err;
-       }
-
-       return 0;
-}
-
-static void vhci_stop(struct usb_hcd *hcd)
-{
-       struct vhci_hcd *vhci = hcd_to_vhci(hcd);
-       int rhport = 0;
-
-       usbip_dbg_vhci_hc("stop VHCI controller\n");
-
-       /* 1. remove the userland interface of vhci_hcd */
-       sysfs_remove_group(&vhci_dev(vhci)->kobj, &dev_attr_group);
-
-       /* 2. shutdown all the ports of vhci_hcd */
-       for (rhport = 0; rhport < VHCI_NPORTS; rhport++) {
-               struct vhci_device *vdev = &vhci->vdev[rhport];
-
-               usbip_event_add(&vdev->ud, VDEV_EVENT_REMOVED);
-               usbip_stop_eh(&vdev->ud);
-       }
-}
-
-static int vhci_get_frame_number(struct usb_hcd *hcd)
-{
-       pr_err("Not yet implemented\n");
-       return 0;
-}
-
-#ifdef CONFIG_PM
-
-/* FIXME: suspend/resume */
-static int vhci_bus_suspend(struct usb_hcd *hcd)
-{
-       struct vhci_hcd *vhci = hcd_to_vhci(hcd);
-
-       dev_dbg(&hcd->self.root_hub->dev, "%s\n", __func__);
-
-       spin_lock(&vhci->lock);
-       hcd->state = HC_STATE_SUSPENDED;
-       spin_unlock(&vhci->lock);
-
-       return 0;
-}
-
-static int vhci_bus_resume(struct usb_hcd *hcd)
-{
-       struct vhci_hcd *vhci = hcd_to_vhci(hcd);
-       int rc = 0;
-
-       dev_dbg(&hcd->self.root_hub->dev, "%s\n", __func__);
-
-       spin_lock(&vhci->lock);
-       if (!HCD_HW_ACCESSIBLE(hcd))
-               rc = -ESHUTDOWN;
-       else
-               hcd->state = HC_STATE_RUNNING;
-       spin_unlock(&vhci->lock);
-
-       return rc;
-}
-
-#else
-
-#define vhci_bus_suspend      NULL
-#define vhci_bus_resume       NULL
-#endif
-
-static struct hc_driver vhci_hc_driver = {
-       .description    = driver_name,
-       .product_desc   = driver_desc,
-       .hcd_priv_size  = sizeof(struct vhci_hcd),
-
-       .flags          = HCD_USB2,
-
-       .start          = vhci_start,
-       .stop           = vhci_stop,
-
-       .urb_enqueue    = vhci_urb_enqueue,
-       .urb_dequeue    = vhci_urb_dequeue,
-
-       .get_frame_number = vhci_get_frame_number,
-
-       .hub_status_data = vhci_hub_status,
-       .hub_control    = vhci_hub_control,
-       .bus_suspend    = vhci_bus_suspend,
-       .bus_resume     = vhci_bus_resume,
-};
-
-static int vhci_hcd_probe(struct platform_device *pdev)
-{
-       struct usb_hcd          *hcd;
-       int                     ret;
-
-       usbip_dbg_vhci_hc("name %s id %d\n", pdev->name, pdev->id);
-
-       /*
-        * Allocate and initialize hcd.
-        * Our private data is also allocated automatically.
-        */
-       hcd = usb_create_hcd(&vhci_hc_driver, &pdev->dev, dev_name(&pdev->dev));
-       if (!hcd) {
-               pr_err("create hcd failed\n");
-               return -ENOMEM;
-       }
-       hcd->has_tt = 1;
-
-       /* this is private data for vhci_hcd */
-       the_controller = hcd_to_vhci(hcd);
-
-       /*
-        * Finish generic HCD structure initialization and register.
-        * Call the driver's reset() and start() routines.
-        */
-       ret = usb_add_hcd(hcd, 0, 0);
-       if (ret != 0) {
-               pr_err("usb_add_hcd failed %d\n", ret);
-               usb_put_hcd(hcd);
-               the_controller = NULL;
-               return ret;
-       }
-
-       usbip_dbg_vhci_hc("bye\n");
-       return 0;
-}
-
-static int vhci_hcd_remove(struct platform_device *pdev)
-{
-       struct usb_hcd  *hcd;
-
-       hcd = platform_get_drvdata(pdev);
-       if (!hcd)
-               return 0;
-
-       /*
-        * Disconnects the root hub,
-        * then reverses the effects of usb_add_hcd(),
-        * invoking the HCD's stop() methods.
-        */
-       usb_remove_hcd(hcd);
-       usb_put_hcd(hcd);
-       the_controller = NULL;
-
-       return 0;
-}
-
-#ifdef CONFIG_PM
-
-/* what should happen for USB/IP under suspend/resume? */
-static int vhci_hcd_suspend(struct platform_device *pdev, pm_message_t state)
-{
-       struct usb_hcd *hcd;
-       int rhport = 0;
-       int connected = 0;
-       int ret = 0;
-
-       hcd = platform_get_drvdata(pdev);
-
-       spin_lock(&the_controller->lock);
-
-       for (rhport = 0; rhport < VHCI_NPORTS; rhport++)
-               if (the_controller->port_status[rhport] &
-                   USB_PORT_STAT_CONNECTION)
-                       connected += 1;
-
-       spin_unlock(&the_controller->lock);
-
-       if (connected > 0) {
-               dev_info(&pdev->dev,
-                        "We have %d active connection%s. Do not suspend.\n",
-                        connected, (connected == 1 ? "" : "s"));
-               ret =  -EBUSY;
-       } else {
-               dev_info(&pdev->dev, "suspend vhci_hcd");
-               clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-       }
-
-       return ret;
-}
-
-static int vhci_hcd_resume(struct platform_device *pdev)
-{
-       struct usb_hcd *hcd;
-
-       dev_dbg(&pdev->dev, "%s\n", __func__);
-
-       hcd = platform_get_drvdata(pdev);
-       set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-       usb_hcd_poll_rh_status(hcd);
-
-       return 0;
-}
-
-#else
-
-#define vhci_hcd_suspend       NULL
-#define vhci_hcd_resume                NULL
-
-#endif
-
-static struct platform_driver vhci_driver = {
-       .probe  = vhci_hcd_probe,
-       .remove = vhci_hcd_remove,
-       .suspend = vhci_hcd_suspend,
-       .resume = vhci_hcd_resume,
-       .driver = {
-               .name = driver_name,
-               .owner = THIS_MODULE,
-       },
-};
-
-/*
- * The VHCI 'device' is 'virtual'; not a real plug&play hardware.
- * We need to add this virtual device as a platform device arbitrarily:
- *     1. platform_device_register()
- */
-static void the_pdev_release(struct device *dev)
-{
-}
-
-static struct platform_device the_pdev = {
-       /* should be the same name as driver_name */
-       .name = driver_name,
-       .id = -1,
-       .dev = {
-               .release = the_pdev_release,
-       },
-};
-
-static int __init vhci_hcd_init(void)
-{
-       int ret;
-
-       if (usb_disabled())
-               return -ENODEV;
-
-       ret = platform_driver_register(&vhci_driver);
-       if (ret)
-               goto err_driver_register;
-
-       ret = platform_device_register(&the_pdev);
-       if (ret)
-               goto err_platform_device_register;
-
-       pr_info(DRIVER_DESC " v" USBIP_VERSION "\n");
-       return ret;
-
-err_platform_device_register:
-       platform_driver_unregister(&vhci_driver);
-err_driver_register:
-       return ret;
-}
-
-static void __exit vhci_hcd_exit(void)
-{
-       platform_device_unregister(&the_pdev);
-       platform_driver_unregister(&vhci_driver);
-}
-
-module_init(vhci_hcd_init);
-module_exit(vhci_hcd_exit);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-MODULE_VERSION(USBIP_VERSION);
diff --git a/drivers/staging/usbip/vhci_rx.c b/drivers/staging/usbip/vhci_rx.c
deleted file mode 100644 (file)
index 00e4a54..0000000
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * Copyright (C) 2003-2008 Takahiro Hirofuchi
- *
- * This 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 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/kthread.h>
-#include <linux/slab.h>
-
-#include "usbip_common.h"
-#include "vhci.h"
-
-/* get URB from transmitted urb queue. caller must hold vdev->priv_lock */
-struct urb *pickup_urb_and_free_priv(struct vhci_device *vdev, __u32 seqnum)
-{
-       struct vhci_priv *priv, *tmp;
-       struct urb *urb = NULL;
-       int status;
-
-       list_for_each_entry_safe(priv, tmp, &vdev->priv_rx, list) {
-               if (priv->seqnum != seqnum)
-                       continue;
-
-               urb = priv->urb;
-               status = urb->status;
-
-               usbip_dbg_vhci_rx("find urb %p vurb %p seqnum %u\n",
-                               urb, priv, seqnum);
-
-               switch (status) {
-               case -ENOENT:
-                       /* fall through */
-               case -ECONNRESET:
-                       dev_info(&urb->dev->dev,
-                                "urb %p was unlinked %ssynchronuously.\n", urb,
-                                status == -ENOENT ? "" : "a");
-                       break;
-               case -EINPROGRESS:
-                       /* no info output */
-                       break;
-               default:
-                       dev_info(&urb->dev->dev,
-                                "urb %p may be in a error, status %d\n", urb,
-                                status);
-               }
-
-               list_del(&priv->list);
-               kfree(priv);
-               urb->hcpriv = NULL;
-
-               break;
-       }
-
-       return urb;
-}
-
-static void vhci_recv_ret_submit(struct vhci_device *vdev,
-                                struct usbip_header *pdu)
-{
-       struct usbip_device *ud = &vdev->ud;
-       struct urb *urb;
-
-       spin_lock(&vdev->priv_lock);
-       urb = pickup_urb_and_free_priv(vdev, pdu->base.seqnum);
-       spin_unlock(&vdev->priv_lock);
-
-       if (!urb) {
-               pr_err("cannot find a urb of seqnum %u\n", pdu->base.seqnum);
-               pr_info("max seqnum %d\n",
-                       atomic_read(&the_controller->seqnum));
-               usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
-               return;
-       }
-
-       /* unpack the pdu to a urb */
-       usbip_pack_pdu(pdu, urb, USBIP_RET_SUBMIT, 0);
-
-       /* recv transfer buffer */
-       if (usbip_recv_xbuff(ud, urb) < 0)
-               return;
-
-       /* recv iso_packet_descriptor */
-       if (usbip_recv_iso(ud, urb) < 0)
-               return;
-
-       /* restore the padding in iso packets */
-       usbip_pad_iso(ud, urb);
-
-       if (usbip_dbg_flag_vhci_rx)
-               usbip_dump_urb(urb);
-
-       usbip_dbg_vhci_rx("now giveback urb %p\n", urb);
-
-       spin_lock(&the_controller->lock);
-       usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb);
-       spin_unlock(&the_controller->lock);
-
-       usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, urb->status);
-
-       usbip_dbg_vhci_rx("Leave\n");
-}
-
-static struct vhci_unlink *dequeue_pending_unlink(struct vhci_device *vdev,
-                                                 struct usbip_header *pdu)
-{
-       struct vhci_unlink *unlink, *tmp;
-
-       spin_lock(&vdev->priv_lock);
-
-       list_for_each_entry_safe(unlink, tmp, &vdev->unlink_rx, list) {
-               pr_info("unlink->seqnum %lu\n", unlink->seqnum);
-               if (unlink->seqnum == pdu->base.seqnum) {
-                       usbip_dbg_vhci_rx("found pending unlink, %lu\n",
-                                         unlink->seqnum);
-                       list_del(&unlink->list);
-
-                       spin_unlock(&vdev->priv_lock);
-                       return unlink;
-               }
-       }
-
-       spin_unlock(&vdev->priv_lock);
-
-       return NULL;
-}
-
-static void vhci_recv_ret_unlink(struct vhci_device *vdev,
-                                struct usbip_header *pdu)
-{
-       struct vhci_unlink *unlink;
-       struct urb *urb;
-
-       usbip_dump_header(pdu);
-
-       unlink = dequeue_pending_unlink(vdev, pdu);
-       if (!unlink) {
-               pr_info("cannot find the pending unlink %u\n",
-                       pdu->base.seqnum);
-               return;
-       }
-
-       spin_lock(&vdev->priv_lock);
-       urb = pickup_urb_and_free_priv(vdev, unlink->unlink_seqnum);
-       spin_unlock(&vdev->priv_lock);
-
-       if (!urb) {
-               /*
-                * I get the result of a unlink request. But, it seems that I
-                * already received the result of its submit result and gave
-                * back the URB.
-                */
-               pr_info("the urb (seqnum %d) was already given back\n",
-                       pdu->base.seqnum);
-       } else {
-               usbip_dbg_vhci_rx("now giveback urb %p\n", urb);
-
-               /* If unlink is successful, status is -ECONNRESET */
-               urb->status = pdu->u.ret_unlink.status;
-               pr_info("urb->status %d\n", urb->status);
-
-               spin_lock(&the_controller->lock);
-               usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb);
-               spin_unlock(&the_controller->lock);
-
-               usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb,
-                                    urb->status);
-       }
-
-       kfree(unlink);
-}
-
-static int vhci_priv_tx_empty(struct vhci_device *vdev)
-{
-       int empty = 0;
-
-       spin_lock(&vdev->priv_lock);
-       empty = list_empty(&vdev->priv_rx);
-       spin_unlock(&vdev->priv_lock);
-
-       return empty;
-}
-
-/* recv a pdu */
-static void vhci_rx_pdu(struct usbip_device *ud)
-{
-       int ret;
-       struct usbip_header pdu;
-       struct vhci_device *vdev = container_of(ud, struct vhci_device, ud);
-
-       usbip_dbg_vhci_rx("Enter\n");
-
-       memset(&pdu, 0, sizeof(pdu));
-
-       /* receive a pdu header */
-       ret = usbip_recv(ud->tcp_socket, &pdu, sizeof(pdu));
-       if (ret < 0) {
-               if (ret == -ECONNRESET)
-                       pr_info("connection reset by peer\n");
-               else if (ret == -EAGAIN) {
-                       /* ignore if connection was idle */
-                       if (vhci_priv_tx_empty(vdev))
-                               return;
-                       pr_info("connection timed out with pending urbs\n");
-               } else if (ret != -ERESTARTSYS)
-                       pr_info("xmit failed %d\n", ret);
-
-               usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
-               return;
-       }
-       if (ret == 0) {
-               pr_info("connection closed");
-               usbip_event_add(ud, VDEV_EVENT_DOWN);
-               return;
-       }
-       if (ret != sizeof(pdu)) {
-               pr_err("received pdu size is %d, should be %d\n", ret,
-                      (unsigned int)sizeof(pdu));
-               usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
-               return;
-       }
-
-       usbip_header_correct_endian(&pdu, 0);
-
-       if (usbip_dbg_flag_vhci_rx)
-               usbip_dump_header(&pdu);
-
-       switch (pdu.base.command) {
-       case USBIP_RET_SUBMIT:
-               vhci_recv_ret_submit(vdev, &pdu);
-               break;
-       case USBIP_RET_UNLINK:
-               vhci_recv_ret_unlink(vdev, &pdu);
-               break;
-       default:
-               /* NOT REACHED */
-               pr_err("unknown pdu %u\n", pdu.base.command);
-               usbip_dump_header(&pdu);
-               usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
-               break;
-       }
-}
-
-int vhci_rx_loop(void *data)
-{
-       struct usbip_device *ud = data;
-
-       while (!kthread_should_stop()) {
-               if (usbip_event_happened(ud))
-                       break;
-
-               vhci_rx_pdu(ud);
-       }
-
-       return 0;
-}
diff --git a/drivers/staging/usbip/vhci_sysfs.c b/drivers/staging/usbip/vhci_sysfs.c
deleted file mode 100644 (file)
index 211f43f..0000000
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * Copyright (C) 2003-2008 Takahiro Hirofuchi
- *
- * This 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 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/kthread.h>
-#include <linux/file.h>
-#include <linux/net.h>
-
-#include "usbip_common.h"
-#include "vhci.h"
-
-/* TODO: refine locking ?*/
-
-/* Sysfs entry to show port status */
-static ssize_t status_show(struct device *dev, struct device_attribute *attr,
-                          char *out)
-{
-       char *s = out;
-       int i = 0;
-
-       BUG_ON(!the_controller || !out);
-
-       spin_lock(&the_controller->lock);
-
-       /*
-        * output example:
-        * prt sta spd dev socket           local_busid
-        * 000 004 000 000         c5a7bb80 1-2.3
-        * 001 004 000 000         d8cee980 2-3.4
-        *
-        * IP address can be retrieved from a socket pointer address by looking
-        * up /proc/net/{tcp,tcp6}. Also, a userland program may remember a
-        * port number and its peer IP address.
-        */
-       out += sprintf(out,
-                      "prt sta spd bus dev socket           local_busid\n");
-
-       for (i = 0; i < VHCI_NPORTS; i++) {
-               struct vhci_device *vdev = port_to_vdev(i);
-
-               spin_lock(&vdev->ud.lock);
-               out += sprintf(out, "%03u %03u ", i, vdev->ud.status);
-
-               if (vdev->ud.status == VDEV_ST_USED) {
-                       out += sprintf(out, "%03u %08x ",
-                                      vdev->speed, vdev->devid);
-                       out += sprintf(out, "%16p ", vdev->ud.tcp_socket);
-                       out += sprintf(out, "%s", dev_name(&vdev->udev->dev));
-
-               } else {
-                       out += sprintf(out, "000 000 000 0000000000000000 0-0");
-               }
-
-               out += sprintf(out, "\n");
-               spin_unlock(&vdev->ud.lock);
-       }
-
-       spin_unlock(&the_controller->lock);
-
-       return out - s;
-}
-static DEVICE_ATTR_RO(status);
-
-/* Sysfs entry to shutdown a virtual connection */
-static int vhci_port_disconnect(__u32 rhport)
-{
-       struct vhci_device *vdev;
-
-       usbip_dbg_vhci_sysfs("enter\n");
-
-       /* lock */
-       spin_lock(&the_controller->lock);
-
-       vdev = port_to_vdev(rhport);
-
-       spin_lock(&vdev->ud.lock);
-       if (vdev->ud.status == VDEV_ST_NULL) {
-               pr_err("not connected %d\n", vdev->ud.status);
-
-               /* unlock */
-               spin_unlock(&vdev->ud.lock);
-               spin_unlock(&the_controller->lock);
-
-               return -EINVAL;
-       }
-
-       /* unlock */
-       spin_unlock(&vdev->ud.lock);
-       spin_unlock(&the_controller->lock);
-
-       usbip_event_add(&vdev->ud, VDEV_EVENT_DOWN);
-
-       return 0;
-}
-
-static ssize_t store_detach(struct device *dev, struct device_attribute *attr,
-                           const char *buf, size_t count)
-{
-       int err;
-       __u32 rhport = 0;
-
-       if (sscanf(buf, "%u", &rhport) != 1)
-               return -EINVAL;
-
-       /* check rhport */
-       if (rhport >= VHCI_NPORTS) {
-               dev_err(dev, "invalid port %u\n", rhport);
-               return -EINVAL;
-       }
-
-       err = vhci_port_disconnect(rhport);
-       if (err < 0)
-               return -EINVAL;
-
-       usbip_dbg_vhci_sysfs("Leave\n");
-
-       return count;
-}
-static DEVICE_ATTR(detach, S_IWUSR, NULL, store_detach);
-
-/* Sysfs entry to establish a virtual connection */
-static int valid_args(__u32 rhport, enum usb_device_speed speed)
-{
-       /* check rhport */
-       if (rhport >= VHCI_NPORTS) {
-               pr_err("port %u\n", rhport);
-               return -EINVAL;
-       }
-
-       /* check speed */
-       switch (speed) {
-       case USB_SPEED_LOW:
-       case USB_SPEED_FULL:
-       case USB_SPEED_HIGH:
-       case USB_SPEED_WIRELESS:
-               break;
-       default:
-               pr_err("Failed attach request for unsupported USB speed: %s\n",
-                       usb_speed_string(speed));
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-/*
- * To start a new USB/IP attachment, a userland program needs to setup a TCP
- * connection and then write its socket descriptor with remote device
- * information into this sysfs file.
- *
- * A remote device is virtually attached to the root-hub port of @rhport with
- * @speed. @devid is embedded into a request to specify the remote device in a
- * server host.
- *
- * write() returns 0 on success, else negative errno.
- */
-static ssize_t store_attach(struct device *dev, struct device_attribute *attr,
-                           const char *buf, size_t count)
-{
-       struct vhci_device *vdev;
-       struct socket *socket;
-       int sockfd = 0;
-       __u32 rhport = 0, devid = 0, speed = 0;
-       int err;
-
-       /*
-        * @rhport: port number of vhci_hcd
-        * @sockfd: socket descriptor of an established TCP connection
-        * @devid: unique device identifier in a remote host
-        * @speed: usb device speed in a remote host
-        */
-       if (sscanf(buf, "%u %u %u %u", &rhport, &sockfd, &devid, &speed) != 4)
-               return -EINVAL;
-
-       usbip_dbg_vhci_sysfs("rhport(%u) sockfd(%u) devid(%u) speed(%u)\n",
-                            rhport, sockfd, devid, speed);
-
-       /* check received parameters */
-       if (valid_args(rhport, speed) < 0)
-               return -EINVAL;
-
-       /* Extract socket from fd. */
-       socket = sockfd_lookup(sockfd, &err);
-       if (!socket)
-               return -EINVAL;
-
-       /* now need lock until setting vdev status as used */
-
-       /* begin a lock */
-       spin_lock(&the_controller->lock);
-       vdev = port_to_vdev(rhport);
-       spin_lock(&vdev->ud.lock);
-
-       if (vdev->ud.status != VDEV_ST_NULL) {
-               /* end of the lock */
-               spin_unlock(&vdev->ud.lock);
-               spin_unlock(&the_controller->lock);
-
-               sockfd_put(socket);
-
-               dev_err(dev, "port %d already used\n", rhport);
-               return -EINVAL;
-       }
-
-       dev_info(dev,
-                "rhport(%u) sockfd(%d) devid(%u) speed(%u) speed_str(%s)\n",
-                rhport, sockfd, devid, speed, usb_speed_string(speed));
-
-       vdev->devid         = devid;
-       vdev->speed         = speed;
-       vdev->ud.tcp_socket = socket;
-       vdev->ud.status     = VDEV_ST_NOTASSIGNED;
-
-       spin_unlock(&vdev->ud.lock);
-       spin_unlock(&the_controller->lock);
-       /* end the lock */
-
-       vdev->ud.tcp_rx = kthread_get_run(vhci_rx_loop, &vdev->ud, "vhci_rx");
-       vdev->ud.tcp_tx = kthread_get_run(vhci_tx_loop, &vdev->ud, "vhci_tx");
-
-       rh_port_connect(rhport, speed);
-
-       return count;
-}
-static DEVICE_ATTR(attach, S_IWUSR, NULL, store_attach);
-
-static struct attribute *dev_attrs[] = {
-       &dev_attr_status.attr,
-       &dev_attr_detach.attr,
-       &dev_attr_attach.attr,
-       &dev_attr_usbip_debug.attr,
-       NULL,
-};
-
-const struct attribute_group dev_attr_group = {
-       .attrs = dev_attrs,
-};
diff --git a/drivers/staging/usbip/vhci_tx.c b/drivers/staging/usbip/vhci_tx.c
deleted file mode 100644 (file)
index 409fd99..0000000
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Copyright (C) 2003-2008 Takahiro Hirofuchi
- *
- * This 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 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/kthread.h>
-#include <linux/slab.h>
-
-#include "usbip_common.h"
-#include "vhci.h"
-
-static void setup_cmd_submit_pdu(struct usbip_header *pdup,  struct urb *urb)
-{
-       struct vhci_priv *priv = ((struct vhci_priv *)urb->hcpriv);
-       struct vhci_device *vdev = priv->vdev;
-
-       usbip_dbg_vhci_tx("URB, local devnum %u, remote devid %u\n",
-                         usb_pipedevice(urb->pipe), vdev->devid);
-
-       pdup->base.command   = USBIP_CMD_SUBMIT;
-       pdup->base.seqnum    = priv->seqnum;
-       pdup->base.devid     = vdev->devid;
-       pdup->base.direction = usb_pipein(urb->pipe) ?
-               USBIP_DIR_IN : USBIP_DIR_OUT;
-       pdup->base.ep        = usb_pipeendpoint(urb->pipe);
-
-       usbip_pack_pdu(pdup, urb, USBIP_CMD_SUBMIT, 1);
-
-       if (urb->setup_packet)
-               memcpy(pdup->u.cmd_submit.setup, urb->setup_packet, 8);
-}
-
-static struct vhci_priv *dequeue_from_priv_tx(struct vhci_device *vdev)
-{
-       struct vhci_priv *priv, *tmp;
-
-       spin_lock(&vdev->priv_lock);
-
-       list_for_each_entry_safe(priv, tmp, &vdev->priv_tx, list) {
-               list_move_tail(&priv->list, &vdev->priv_rx);
-               spin_unlock(&vdev->priv_lock);
-               return priv;
-       }
-
-       spin_unlock(&vdev->priv_lock);
-
-       return NULL;
-}
-
-static int vhci_send_cmd_submit(struct vhci_device *vdev)
-{
-       struct vhci_priv *priv = NULL;
-
-       struct msghdr msg;
-       struct kvec iov[3];
-       size_t txsize;
-
-       size_t total_size = 0;
-
-       while ((priv = dequeue_from_priv_tx(vdev)) != NULL) {
-               int ret;
-               struct urb *urb = priv->urb;
-               struct usbip_header pdu_header;
-               struct usbip_iso_packet_descriptor *iso_buffer = NULL;
-
-               txsize = 0;
-               memset(&pdu_header, 0, sizeof(pdu_header));
-               memset(&msg, 0, sizeof(msg));
-               memset(&iov, 0, sizeof(iov));
-
-               usbip_dbg_vhci_tx("setup txdata urb %p\n", urb);
-
-               /* 1. setup usbip_header */
-               setup_cmd_submit_pdu(&pdu_header, urb);
-               usbip_header_correct_endian(&pdu_header, 1);
-
-               iov[0].iov_base = &pdu_header;
-               iov[0].iov_len  = sizeof(pdu_header);
-               txsize += sizeof(pdu_header);
-
-               /* 2. setup transfer buffer */
-               if (!usb_pipein(urb->pipe) && urb->transfer_buffer_length > 0) {
-                       iov[1].iov_base = urb->transfer_buffer;
-                       iov[1].iov_len  = urb->transfer_buffer_length;
-                       txsize += urb->transfer_buffer_length;
-               }
-
-               /* 3. setup iso_packet_descriptor */
-               if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
-                       ssize_t len = 0;
-
-                       iso_buffer = usbip_alloc_iso_desc_pdu(urb, &len);
-                       if (!iso_buffer) {
-                               usbip_event_add(&vdev->ud,
-                                               SDEV_EVENT_ERROR_MALLOC);
-                               return -1;
-                       }
-
-                       iov[2].iov_base = iso_buffer;
-                       iov[2].iov_len  = len;
-                       txsize += len;
-               }
-
-               ret = kernel_sendmsg(vdev->ud.tcp_socket, &msg, iov, 3, txsize);
-               if (ret != txsize) {
-                       pr_err("sendmsg failed!, ret=%d for %zd\n", ret,
-                              txsize);
-                       kfree(iso_buffer);
-                       usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_TCP);
-                       return -1;
-               }
-
-               kfree(iso_buffer);
-               usbip_dbg_vhci_tx("send txdata\n");
-
-               total_size += txsize;
-       }
-
-       return total_size;
-}
-
-static struct vhci_unlink *dequeue_from_unlink_tx(struct vhci_device *vdev)
-{
-       struct vhci_unlink *unlink, *tmp;
-
-       spin_lock(&vdev->priv_lock);
-
-       list_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) {
-               list_move_tail(&unlink->list, &vdev->unlink_rx);
-               spin_unlock(&vdev->priv_lock);
-               return unlink;
-       }
-
-       spin_unlock(&vdev->priv_lock);
-
-       return NULL;
-}
-
-static int vhci_send_cmd_unlink(struct vhci_device *vdev)
-{
-       struct vhci_unlink *unlink = NULL;
-
-       struct msghdr msg;
-       struct kvec iov[3];
-       size_t txsize;
-
-       size_t total_size = 0;
-
-       while ((unlink = dequeue_from_unlink_tx(vdev)) != NULL) {
-               int ret;
-               struct usbip_header pdu_header;
-
-               txsize = 0;
-               memset(&pdu_header, 0, sizeof(pdu_header));
-               memset(&msg, 0, sizeof(msg));
-               memset(&iov, 0, sizeof(iov));
-
-               usbip_dbg_vhci_tx("setup cmd unlink, %lu\n", unlink->seqnum);
-
-               /* 1. setup usbip_header */
-               pdu_header.base.command = USBIP_CMD_UNLINK;
-               pdu_header.base.seqnum  = unlink->seqnum;
-               pdu_header.base.devid   = vdev->devid;
-               pdu_header.base.ep      = 0;
-               pdu_header.u.cmd_unlink.seqnum = unlink->unlink_seqnum;
-
-               usbip_header_correct_endian(&pdu_header, 1);
-
-               iov[0].iov_base = &pdu_header;
-               iov[0].iov_len  = sizeof(pdu_header);
-               txsize += sizeof(pdu_header);
-
-               ret = kernel_sendmsg(vdev->ud.tcp_socket, &msg, iov, 1, txsize);
-               if (ret != txsize) {
-                       pr_err("sendmsg failed!, ret=%d for %zd\n", ret,
-                              txsize);
-                       usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_TCP);
-                       return -1;
-               }
-
-               usbip_dbg_vhci_tx("send txdata\n");
-
-               total_size += txsize;
-       }
-
-       return total_size;
-}
-
-int vhci_tx_loop(void *data)
-{
-       struct usbip_device *ud = data;
-       struct vhci_device *vdev = container_of(ud, struct vhci_device, ud);
-
-       while (!kthread_should_stop()) {
-               if (vhci_send_cmd_submit(vdev) < 0)
-                       break;
-
-               if (vhci_send_cmd_unlink(vdev) < 0)
-                       break;
-
-               wait_event_interruptible(vdev->waitq_tx,
-                                        (!list_empty(&vdev->priv_tx) ||
-                                         !list_empty(&vdev->unlink_tx) ||
-                                         kthread_should_stop()));
-
-               usbip_dbg_vhci_tx("pending urbs ?, now wake up\n");
-       }
-
-       return 0;
-}
index 3727f6d25cf1af074ce35f1336453e6b7312a965..8942dcb44180339ffb9cd6318a3b29d3aef06241 100644 (file)
@@ -422,6 +422,7 @@ static int prism2_scan(struct wiphy *wiphy,
                                                      IEEE80211_BAND_2GHZ);
                bss = cfg80211_inform_bss(wiphy,
                        ieee80211_get_channel(wiphy, freq),
+                       CFG80211_BSS_FTYPE_UNKNOWN,
                        (const u8 *) &(msg2.bssid.data.data),
                        msg2.timestamp.data, msg2.capinfo.data,
                        msg2.beaconperiod.data,
index 8fcf8a7b6c2264d75f98d919b4bc88e7b1a3e4ae..9562cd026dc01754144edab74f981313f837b507 100644 (file)
@@ -150,7 +150,26 @@ int tb_path_activate(struct tb_path *path)
 
        /* Activate hops. */
        for (i = path->path_length - 1; i >= 0; i--) {
-               struct tb_regs_hop hop;
+               struct tb_regs_hop hop = { 0 };
+
+               /*
+                * We do (currently) not tear down paths setup by the firmeware.
+                * If a firmware device is unplugged and plugged in again then
+                * it can happen that we reuse some of the hops from the (now
+                * defunct) firmeware path. This causes the hotplug operation to
+                * fail (the pci device does not show up). Clearing the hop
+                * before overwriting it fixes the problem.
+                *
+                * Should be removed once we discover and tear down firmeware
+                * paths.
+                */
+               res = tb_port_write(path->hops[i].in_port, &hop, TB_CFG_HOPS,
+                                   2 * path->hops[i].in_hop_index, 2);
+               if (res) {
+                       __tb_path_deactivate_hops(path, i);
+                       __tb_path_deallocate_nfc(path, 0);
+                       goto err;
+               }
 
                /* dword 0 */
                hop.next_hop = path->hops[i].next_hop_index;
index e0cad4418085c5c136c1e8db3852803d74d3b822..cf1b19bca3064621a8d772b76a37f504346bb848 100644 (file)
@@ -92,6 +92,8 @@ source "drivers/usb/storage/Kconfig"
 
 source "drivers/usb/image/Kconfig"
 
+source "drivers/usb/usbip/Kconfig"
+
 endif
 
 source "drivers/usb/musb/Kconfig"
index 3cba892b83a2f5b29ec0e03e69a5393a2bb3e875..d7be717780598ec5668506a5c0e2e33a224b0ce3 100644 (file)
@@ -60,3 +60,5 @@ obj-$(CONFIG_USB_RENESAS_USBHS)       += renesas_usbhs/
 obj-$(CONFIG_USB_GADGET)       += gadget/
 
 obj-$(CONFIG_USB_COMMON)       += common/
+
+obj-$(CONFIG_USBIP_CORE)       += usbip/
index 8a4dcbc7a75fb7f1f6a780af6fa65698af952bf2..46f5161c78913c75678ae3416f4031099b880090 100644 (file)
@@ -1728,8 +1728,14 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
         * - Change autosuspend delay of hub can avoid unnecessary auto
         *   suspend timer for hub, also may decrease power consumption
         *   of USB bus.
+        *
+        * - If user has indicated to prevent autosuspend by passing
+        *   usbcore.autosuspend = -1 then keep autosuspend disabled.
         */
-       pm_runtime_set_autosuspend_delay(&hdev->dev, 0);
+#ifdef CONFIG_PM_RUNTIME
+       if (hdev->dev.power.autosuspend_delay >= 0)
+               pm_runtime_set_autosuspend_delay(&hdev->dev, 0);
+#endif
 
        /*
         * Hubs have proper suspend/resume support, except for root hubs
@@ -2107,8 +2113,8 @@ void usb_disconnect(struct usb_device **pdev)
 {
        struct usb_port *port_dev = NULL;
        struct usb_device *udev = *pdev;
-       struct usb_hub *hub;
-       int port1;
+       struct usb_hub *hub = NULL;
+       int port1 = 1;
 
        /* mark the device as inactive, so any further urb submissions for
         * this device (and any of its children) will fail immediately.
@@ -4631,9 +4637,7 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
                        if (status != -ENODEV &&
                                port1 != unreliable_port &&
                                printk_ratelimit())
-                               dev_err(&udev->dev, "connect-debounce failed, port %d disabled\n",
-                                       port1);
-
+                               dev_err(&port_dev->dev, "connect-debounce failed\n");
                        portstatus &= ~USB_PORT_STAT_CONNECTION;
                        unreliable_port = port1;
                } else {
index 0ba9c335b5849d4960fe4deced4a21b20076fdc0..7c9618e916e23cd7eca1cc6ae098edf999a4aa06 100644 (file)
@@ -1901,7 +1901,7 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
 static void s3c_hsotg_irq_enumdone(struct s3c_hsotg *hsotg)
 {
        u32 dsts = readl(hsotg->regs + DSTS);
-       int ep0_mps = 0, ep_mps;
+       int ep0_mps = 0, ep_mps = 8;
 
        /*
         * This should signal the finish of the enumeration phase
index ef4936ff626c3cdea2bd0bc6e0a7e7328481a3a7..9dcfbe7cd5f5d5cfc58239ee578cd68cae09a63f 100644 (file)
@@ -425,7 +425,7 @@ static void dwc3_omap_set_utmi_mode(struct dwc3_omap *omap)
 
 static int dwc3_omap_extcon_register(struct dwc3_omap *omap)
 {
-       u32                     ret;
+       int                     ret;
        struct device_node      *node = omap->dev->of_node;
        struct extcon_dev       *edev;
 
index a186afeaa7001f3f81abb4f95d9edd3099477867..9add915d41f73521d369279bdbcd443d9d552fa2 100644 (file)
@@ -3,7 +3,7 @@
 #
 subdir-ccflags-$(CONFIG_USB_GADGET_DEBUG)      := -DDEBUG
 subdir-ccflags-$(CONFIG_USB_GADGET_VERBOSE)    += -DVERBOSE_DEBUG
-ccflags-y                              += -I$(PWD)/drivers/usb/gadget/udc
+ccflags-y                              += -Idrivers/usb/gadget/udc
 
 obj-$(CONFIG_USB_LIBCOMPOSITE) += libcomposite.o
 libcomposite-y                 := usbstring.o config.o epautoconf.o
index 6d91f21b52a6301c303aac0a4f62e572d83c02aa..83ae1065149d3dd21f91bef6902168b9908f73ff 100644 (file)
@@ -2,8 +2,8 @@
 # USB peripheral controller drivers
 #
 
-ccflags-y                      := -I$(PWD)/drivers/usb/gadget/
-ccflags-y                      += -I$(PWD)/drivers/usb/gadget/udc/
+ccflags-y                      := -Idrivers/usb/gadget/
+ccflags-y                      += -Idrivers/usb/gadget/udc/
 
 # USB Functions
 usb_f_acm-y                    := f_acm.o
index bcdc882cd4157af2a0bd56a89248b7d3969d4b35..146f48cc65d7fb9c000565448121337f914c694c 100644 (file)
@@ -1101,7 +1101,15 @@ static void ncm_tx_tasklet(unsigned long data)
        /* Only send if data is available. */
        if (ncm->skb_tx_data) {
                ncm->timer_force_tx = true;
+
+               /* XXX This allowance of a NULL skb argument to ndo_start_xmit
+                * XXX is not sane.  The gadget layer should be redesigned so
+                * XXX that the dev->wrap() invocations to build SKBs is transparent
+                * XXX and performed in some way outside of the ndo_start_xmit
+                * XXX interface.
+                */
                ncm->netdev->netdev_ops->ndo_start_xmit(NULL, ncm->netdev);
+
                ncm->timer_force_tx = false;
        }
 }
index d50adda913cfa6d57e1e6191ab5444d6981af47a..6e6f87656e7b0f5795caa17f387aa6cf89de2d41 100644 (file)
@@ -1127,10 +1127,7 @@ void gether_disconnect(struct gether *link)
 
        DBG(dev, "%s\n", __func__);
 
-       netif_tx_lock(dev->net);
        netif_stop_queue(dev->net);
-       netif_tx_unlock(dev->net);
-
        netif_carrier_off(dev->net);
 
        /* disable endpoints, forcing (synchronous) completion
index 71e896d4c5ae481d189e582609d8cb456a8187c3..a5eb9a3fbb7a3c7c40306e516abfd5244986f436 100644 (file)
@@ -195,6 +195,7 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
                printk(KERN_INFO "Failed to queue request (%d).\n", ret);
                usb_ep_set_halt(ep);
                spin_unlock_irqrestore(&video->queue.irqlock, flags);
+               uvc_queue_cancel(queue, 0);
                goto requeue;
        }
        spin_unlock_irqrestore(&video->queue.irqlock, flags);
@@ -281,6 +282,7 @@ error:
 static int
 uvc_video_pump(struct uvc_video *video)
 {
+       struct uvc_video_queue *queue = &video->queue;
        struct usb_request *req;
        struct uvc_buffer *buf;
        unsigned long flags;
@@ -322,6 +324,7 @@ uvc_video_pump(struct uvc_video *video)
                        printk(KERN_INFO "Failed to queue request (%d)\n", ret);
                        usb_ep_set_halt(video->ep);
                        spin_unlock_irqrestore(&video->queue.irqlock, flags);
+                       uvc_queue_cancel(queue, 0);
                        break;
                }
                spin_unlock_irqrestore(&video->queue.irqlock, flags);
index a11aad5635df415422feb5f0a32d8d269cc14b6d..edba2d1ee0f3fc65e2af5366b503245857080bf8 100644 (file)
@@ -2,9 +2,9 @@
 # USB gadget drivers
 #
 
-ccflags-y                      := -I$(PWD)/drivers/usb/gadget/
-ccflags-y                      += -I$(PWD)/drivers/usb/gadget/udc/
-ccflags-y                      += -I$(PWD)/drivers/usb/gadget/function/
+ccflags-y                      := -Idrivers/usb/gadget/
+ccflags-y                      += -Idrivers/usb/gadget/udc/
+ccflags-y                      += -Idrivers/usb/gadget/function/
 
 g_zero-y                       := zero.o
 g_audio-y                      := audio.o
index 986fc511a2edcdab4afc6a09780d2b1632159f75..225e385a616009747a42b5117769e316c7638fc6 100644 (file)
@@ -222,10 +222,12 @@ static void dbgp_unbind(struct usb_gadget *gadget)
 {
 #ifdef CONFIG_USB_G_DBGP_SERIAL
        kfree(dbgp.serial);
+       dbgp.serial = NULL;
 #endif
        if (dbgp.req) {
                kfree(dbgp.req->buf);
                usb_ep_free_request(gadget->ep0, dbgp.req);
+               dbgp.req = NULL;
        }
 
        gadget->ep0->driver_data = NULL;
index 2e4ce7704908bc78e4ed2385842a1e6dbec1d59c..e96077b8bf7922b89b5feda9a9c34b3de843ab55 100644 (file)
@@ -440,7 +440,7 @@ ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
 
        value = -ENOMEM;
        kbuf = memdup_user(buf, len);
-       if (!kbuf) {
+       if (IS_ERR(kbuf)) {
                value = PTR_ERR(kbuf);
                goto free1;
        }
index 5151f947a4f56119e56c9e6d445df29b4f1a6314..34ebaa68504c1b68c5e697ccfe0ed74524f1a4fc 100644 (file)
@@ -332,7 +332,7 @@ config USB_GOKU
           gadget drivers to also be dynamically linked.
 
 config USB_EG20T
-       tristate "Intel EG20T PCH/LAPIS Semiconductor IOH(ML7213/ML7831) UDC"
+       tristate "Intel QUARK X1000/EG20T PCH/LAPIS Semiconductor IOH(ML7213/ML7831) UDC"
        depends on PCI
        help
          This is a USB device driver for EG20T PCH.
@@ -353,6 +353,7 @@ config USB_EG20T
          ML7213/ML7831 is companion chip for Intel Atom E6xx series.
          ML7213/ML7831 is completely compatible for Intel EG20T PCH.
 
+         This driver can be used with Intel's Quark X1000 SOC platform
 #
 # LAST -- dummy/emulated controller
 #
index 906e65f0e4fa7b8c225e4c75ad80666b6dd78085..c9fe67e29d35fcbe420b04a79f6797d531b852e9 100644 (file)
@@ -1661,7 +1661,7 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
        if (dma_status) {
                int i;
 
-               for (i = 1; i < USBA_NR_DMAS; i++)
+               for (i = 1; i <= USBA_NR_DMAS; i++)
                        if (dma_status & (1 << i))
                                usba_dma_irq(udc, &udc->usba_ep[i]);
        }
index d40255f784df6824d4d3a6d00ca58bf15f319292..5c5d1adda7eb23c1a57e4ee8ea5d8696c361ebbb 100644 (file)
@@ -1398,13 +1398,17 @@ static int fusb300_probe(struct platform_device *pdev)
 
        /* initialize udc */
        fusb300 = kzalloc(sizeof(struct fusb300), GFP_KERNEL);
-       if (fusb300 == NULL)
+       if (fusb300 == NULL) {
+               ret = -ENOMEM;
                goto clean_up;
+       }
 
        for (i = 0; i < FUSB300_MAX_NUM_EP; i++) {
                _ep[i] = kzalloc(sizeof(struct fusb300_ep), GFP_KERNEL);
-               if (_ep[i] == NULL)
+               if (_ep[i] == NULL) {
+                       ret = -ENOMEM;
                        goto clean_up;
+               }
                fusb300->ep[i] = _ep[i];
        }
 
index eb8c3bedb57abc20e7a9ccd4913700406b1958d5..460d953c91b6c9b540d2af185b3f2664ea39613b 100644 (file)
@@ -343,6 +343,7 @@ struct pch_vbus_gpio_data {
  * @setup_data:                Received setup data
  * @phys_addr:         of device memory
  * @base_addr:         for mapped device memory
+ * @bar:               Indicates which PCI BAR for USB regs
  * @irq:               IRQ line for the device
  * @cfg_data:          current cfg, intf, and alt in use
  * @vbus_gpio:         GPIO informaton for detecting VBUS
@@ -370,14 +371,17 @@ struct pch_udc_dev {
        struct usb_ctrlrequest          setup_data;
        unsigned long                   phys_addr;
        void __iomem                    *base_addr;
+       unsigned                        bar;
        unsigned                        irq;
        struct pch_udc_cfg_data         cfg_data;
        struct pch_vbus_gpio_data       vbus_gpio;
 };
 #define to_pch_udc(g)  (container_of((g), struct pch_udc_dev, gadget))
 
+#define PCH_UDC_PCI_BAR_QUARK_X1000    0
 #define PCH_UDC_PCI_BAR                        1
 #define PCI_DEVICE_ID_INTEL_EG20T_UDC  0x8808
+#define PCI_DEVICE_ID_INTEL_QUARK_X1000_UDC    0x0939
 #define PCI_VENDOR_ID_ROHM             0x10DB
 #define PCI_DEVICE_ID_ML7213_IOH_UDC   0x801D
 #define PCI_DEVICE_ID_ML7831_IOH_UDC   0x8808
@@ -3076,7 +3080,7 @@ static void pch_udc_remove(struct pci_dev *pdev)
                iounmap(dev->base_addr);
        if (dev->mem_region)
                release_mem_region(dev->phys_addr,
-                                  pci_resource_len(pdev, PCH_UDC_PCI_BAR));
+                                  pci_resource_len(pdev, dev->bar));
        if (dev->active)
                pci_disable_device(pdev);
        kfree(dev);
@@ -3144,9 +3148,15 @@ static int pch_udc_probe(struct pci_dev *pdev,
        dev->active = 1;
        pci_set_drvdata(pdev, dev);
 
+       /* Determine BAR based on PCI ID */
+       if (id->device == PCI_DEVICE_ID_INTEL_QUARK_X1000_UDC)
+               dev->bar = PCH_UDC_PCI_BAR_QUARK_X1000;
+       else
+               dev->bar = PCH_UDC_PCI_BAR;
+
        /* PCI resource allocation */
-       resource = pci_resource_start(pdev, 1);
-       len = pci_resource_len(pdev, 1);
+       resource = pci_resource_start(pdev, dev->bar);
+       len = pci_resource_len(pdev, dev->bar);
 
        if (!request_mem_region(resource, len, KBUILD_MODNAME)) {
                dev_err(&pdev->dev, "%s: pci device used already\n", __func__);
@@ -3211,6 +3221,12 @@ finished:
 }
 
 static const struct pci_device_id pch_udc_pcidev_id[] = {
+       {
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL,
+                          PCI_DEVICE_ID_INTEL_QUARK_X1000_UDC),
+               .class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe,
+               .class_mask = 0xffffffff,
+       },
        {
                PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EG20T_UDC),
                .class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe,
index 46008421c1ec8fad66dca295174460255150e51b..de2a8713b42884994cafda67990e06a2e93fcb23 100644 (file)
@@ -1868,8 +1868,8 @@ static int r8a66597_probe(struct platform_device *pdev)
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        reg = devm_ioremap_resource(&pdev->dev, res);
-       if (!reg)
-               return -ENODEV;
+       if (IS_ERR(reg))
+               return PTR_ERR(reg);
 
        ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        irq = ires->start;
index cc305c71ac3d489d469ec4ca34a03c7861bf122f..6130b757490893a471dd3cbfa33026e8b8738071 100644 (file)
@@ -1230,7 +1230,7 @@ int ehci_hub_control(
                        if (selector == EHSET_TEST_SINGLE_STEP_SET_FEATURE) {
                                spin_unlock_irqrestore(&ehci->lock, flags);
                                retval = ehset_single_step_set_feature(hcd,
-                                                                       wIndex);
+                                                               wIndex + 1);
                                spin_lock_irqsave(&ehci->lock, flags);
                                break;
                        }
index 687d366081557589ad2fa9e33b1a51a0c4499c3e..c22a3e15a16e77b3543921ab8bb4ba2a84268f80 100644 (file)
@@ -101,6 +101,10 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
        /* AMD PLL quirk */
        if (pdev->vendor == PCI_VENDOR_ID_AMD && usb_amd_find_chipset_info())
                xhci->quirks |= XHCI_AMD_PLL_FIX;
+
+       if (pdev->vendor == PCI_VENDOR_ID_AMD)
+               xhci->quirks |= XHCI_TRUST_TX_LENGTH;
+
        if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
                xhci->quirks |= XHCI_LPM_SUPPORT;
                xhci->quirks |= XHCI_INTEL_HOST;
@@ -151,6 +155,11 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
        if (pdev->vendor == PCI_VENDOR_ID_VIA)
                xhci->quirks |= XHCI_RESET_ON_RESUME;
 
+       /* See https://bugzilla.kernel.org/show_bug.cgi?id=79511 */
+       if (pdev->vendor == PCI_VENDOR_ID_VIA &&
+                       pdev->device == 0x3432)
+               xhci->quirks |= XHCI_BROKEN_STREAMS;
+
        if (xhci->quirks & XHCI_RESET_ON_RESUME)
                xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
                                "QUIRK: Resetting on resume");
index 60fb52ae864b0ed15066d6073647224df7fd32ec..abed30b82905737e5565515ca9c7fe8b5e508303 100644 (file)
@@ -364,32 +364,6 @@ static void ring_doorbell_for_active_rings(struct xhci_hcd *xhci,
        }
 }
 
-/*
- * Find the segment that trb is in.  Start searching in start_seg.
- * If we must move past a segment that has a link TRB with a toggle cycle state
- * bit set, then we will toggle the value pointed at by cycle_state.
- */
-static struct xhci_segment *find_trb_seg(
-               struct xhci_segment *start_seg,
-               union xhci_trb  *trb, int *cycle_state)
-{
-       struct xhci_segment *cur_seg = start_seg;
-       struct xhci_generic_trb *generic_trb;
-
-       while (cur_seg->trbs > trb ||
-                       &cur_seg->trbs[TRBS_PER_SEGMENT - 1] < trb) {
-               generic_trb = &cur_seg->trbs[TRBS_PER_SEGMENT - 1].generic;
-               if (generic_trb->field[3] & cpu_to_le32(LINK_TOGGLE))
-                       *cycle_state ^= 0x1;
-               cur_seg = cur_seg->next;
-               if (cur_seg == start_seg)
-                       /* Looped over the entire list.  Oops! */
-                       return NULL;
-       }
-       return cur_seg;
-}
-
-
 static struct xhci_ring *xhci_triad_to_transfer_ring(struct xhci_hcd *xhci,
                unsigned int slot_id, unsigned int ep_index,
                unsigned int stream_id)
@@ -459,9 +433,12 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
        struct xhci_virt_device *dev = xhci->devs[slot_id];
        struct xhci_virt_ep *ep = &dev->eps[ep_index];
        struct xhci_ring *ep_ring;
-       struct xhci_generic_trb *trb;
+       struct xhci_segment *new_seg;
+       union xhci_trb *new_deq;
        dma_addr_t addr;
        u64 hw_dequeue;
+       bool cycle_found = false;
+       bool td_last_trb_found = false;
 
        ep_ring = xhci_triad_to_transfer_ring(xhci, slot_id,
                        ep_index, stream_id);
@@ -486,45 +463,45 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
                hw_dequeue = le64_to_cpu(ep_ctx->deq);
        }
 
-       /* Find virtual address and segment of hardware dequeue pointer */
-       state->new_deq_seg = ep_ring->deq_seg;
-       state->new_deq_ptr = ep_ring->dequeue;
-       while (xhci_trb_virt_to_dma(state->new_deq_seg, state->new_deq_ptr)
-                       != (dma_addr_t)(hw_dequeue & ~0xf)) {
-               next_trb(xhci, ep_ring, &state->new_deq_seg,
-                                       &state->new_deq_ptr);
-               if (state->new_deq_ptr == ep_ring->dequeue) {
-                       WARN_ON(1);
-                       return;
-               }
-       }
+       new_seg = ep_ring->deq_seg;
+       new_deq = ep_ring->dequeue;
+       state->new_cycle_state = hw_dequeue & 0x1;
+
        /*
-        * Find cycle state for last_trb, starting at old cycle state of
-        * hw_dequeue. If there is only one segment ring, find_trb_seg() will
-        * return immediately and cannot toggle the cycle state if this search
-        * wraps around, so add one more toggle manually in that case.
+        * We want to find the pointer, segment and cycle state of the new trb
+        * (the one after current TD's last_trb). We know the cycle state at
+        * hw_dequeue, so walk the ring until both hw_dequeue and last_trb are
+        * found.
         */
-       state->new_cycle_state = hw_dequeue & 0x1;
-       if (ep_ring->first_seg == ep_ring->first_seg->next &&
-                       cur_td->last_trb < state->new_deq_ptr)
-               state->new_cycle_state ^= 0x1;
+       do {
+               if (!cycle_found && xhci_trb_virt_to_dma(new_seg, new_deq)
+                   == (dma_addr_t)(hw_dequeue & ~0xf)) {
+                       cycle_found = true;
+                       if (td_last_trb_found)
+                               break;
+               }
+               if (new_deq == cur_td->last_trb)
+                       td_last_trb_found = true;
 
-       state->new_deq_ptr = cur_td->last_trb;
-       xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
-                       "Finding segment containing last TRB in TD.");
-       state->new_deq_seg = find_trb_seg(state->new_deq_seg,
-                       state->new_deq_ptr, &state->new_cycle_state);
-       if (!state->new_deq_seg) {
-               WARN_ON(1);
-               return;
-       }
+               if (cycle_found &&
+                   TRB_TYPE_LINK_LE32(new_deq->generic.field[3]) &&
+                   new_deq->generic.field[3] & cpu_to_le32(LINK_TOGGLE))
+                       state->new_cycle_state ^= 0x1;
+
+               next_trb(xhci, ep_ring, &new_seg, &new_deq);
+
+               /* Search wrapped around, bail out */
+               if (new_deq == ep->ring->dequeue) {
+                       xhci_err(xhci, "Error: Failed finding new dequeue state\n");
+                       state->new_deq_seg = NULL;
+                       state->new_deq_ptr = NULL;
+                       return;
+               }
+
+       } while (!cycle_found || !td_last_trb_found);
 
-       /* Increment to find next TRB after last_trb. Cycle if appropriate. */
-       trb = &state->new_deq_ptr->generic;
-       if (TRB_TYPE_LINK_LE32(trb->field[3]) &&
-           (trb->field[3] & cpu_to_le32(LINK_TOGGLE)))
-               state->new_cycle_state ^= 0x1;
-       next_trb(xhci, ep_ring, &state->new_deq_seg, &state->new_deq_ptr);
+       state->new_deq_seg = new_seg;
+       state->new_deq_ptr = new_deq;
 
        /* Don't update the ring cycle state for the producer (us). */
        xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
@@ -2487,7 +2464,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
                 * last TRB of the previous TD. The command completion handle
                 * will take care the rest.
                 */
-               if (!event_seg && trb_comp_code == COMP_STOP_INVAL) {
+               if (!event_seg && (trb_comp_code == COMP_STOP ||
+                                  trb_comp_code == COMP_STOP_INVAL)) {
                        ret = 0;
                        goto cleanup;
                }
index b6f21175b872fd0d300968a55e2750e0fd9c69c5..c020b094fe7d952d91f1f977a02d35de52dff451 100644 (file)
@@ -2880,6 +2880,9 @@ void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci,
                        ep_index, ep->stopped_stream, ep->stopped_td,
                        &deq_state);
 
+       if (!deq_state.new_deq_ptr || !deq_state.new_deq_seg)
+               return;
+
        /* HW with the reset endpoint quirk will use the saved dequeue state to
         * issue a configure endpoint command later.
         */
index 06b5d77cd9ade2aba61d5e79d308ae6afdc7e45b..633caf64312232bb7e73954357f1efb66313597a 100644 (file)
@@ -3250,6 +3250,7 @@ static const struct usb_device_id sisusb_table[] = {
        { USB_DEVICE(0x0711, 0x0918) },
        { USB_DEVICE(0x0711, 0x0920) },
        { USB_DEVICE(0x0711, 0x0950) },
+       { USB_DEVICE(0x0711, 0x5200) },
        { USB_DEVICE(0x182d, 0x021c) },
        { USB_DEVICE(0x182d, 0x0269) },
        { }
index 9aad00f11bd5e81fb16a4930c1ba9b0efe951acd..221faed9f07408d5881d1dd6c43270a1a5f1c240 100644 (file)
@@ -96,7 +96,7 @@ static bool ux500_configure_channel(struct dma_channel *channel,
        struct musb *musb = ux500_channel->controller->private_data;
 
        dev_dbg(musb->controller,
-               "packet_sz=%d, mode=%d, dma_addr=0x%llu, len=%d is_tx=%d\n",
+               "packet_sz=%d, mode=%d, dma_addr=0x%llx, len=%d is_tx=%d\n",
                packet_sz, mode, (unsigned long long) dma_addr,
                len, ux500_channel->is_tx);
 
index ea9e705555df67cb32cc9d67f89ef734872ac39d..f4b14bd97e1442a586371943d3bd39897e5b997f 100644 (file)
@@ -260,10 +260,8 @@ static int gpio_vbus_probe(struct platform_device *pdev)
 
        gpio_vbus->phy.otg = devm_kzalloc(&pdev->dev, sizeof(struct usb_otg),
                                          GFP_KERNEL);
-       if (!gpio_vbus->phy.otg) {
-               kfree(gpio_vbus);
+       if (!gpio_vbus->phy.otg)
                return -ENOMEM;
-       }
 
        platform_set_drvdata(pdev, gpio_vbus);
        gpio_vbus->dev = &pdev->dev;
index e4108eec5ef4153c7370f405040618cd1df41114..afc09087ec3630217079dd074f6da406ab3eed68 100644 (file)
@@ -1601,8 +1601,8 @@ static int msm_otg_probe(struct platform_device *pdev)
         */
        if (motg->phy_number) {
                phy_select = devm_ioremap_nocache(&pdev->dev, USB2_PHY_SEL, 4);
-               if (IS_ERR(phy_select))
-                       return PTR_ERR(phy_select);
+               if (!phy_select)
+                       return -ENOMEM;
                /* Enable second PHY with the OTG port */
                writel(0x1, phy_select);
        }
index 68771bfd18253df19dd2f999086611d0314d4b90..80eedd45a20aed05417066229040ccfaf4381b21 100644 (file)
 
 #define EXYNOS5_DRD_PHYPARAM1                  (0x20)
 
-#define PHYPARAM1_PCS_TXDEEMPH_MASK            (0x1f << 0)
+#define PHYPARAM1_PCS_TXDEEMPH_MASK            (0x3f << 0)
 #define PHYPARAM1_PCS_TXDEEMPH                 (0x1c)
 
 #define EXYNOS5_DRD_PHYTERM                    (0x24)
index 6d0f6080eceb309201abb2afae10080c6b67ba84..045cd309367ae7e9df8bbb9726ddb4b99de23ea1 100644 (file)
@@ -232,6 +232,9 @@ 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)) {
                dev_dbg(dev, "unable to find transceiver\n");
+               if (!IS_ERR(phy))
+                       phy = ERR_PTR(-ENODEV);
+
                goto err0;
        }
 
index 216ce30782704d29a922a4a0e7d5df380768cd5d..824ea5e7ec8b7b1b67a7820e6fbb691197aee030 100644 (file)
@@ -146,6 +146,7 @@ static const struct usb_device_id id_table_combined[] = {
        { USB_DEVICE(FTDI_VID, FTDI_AMC232_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_CANUSB_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_CANDAPTER_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_BM_ATOM_NANO_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_NXTCAM_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_EV3CON_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_0_PID) },
@@ -934,6 +935,8 @@ static const struct usb_device_id id_table_combined[] = {
        { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_842_2_PID) },
        { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_842_3_PID) },
        { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_842_4_PID) },
+       /* ekey Devices */
+       { USB_DEVICE(FTDI_VID, FTDI_EKEY_CONV_USB_PID) },
        /* Infineon Devices */
        { USB_DEVICE_INTERFACE_NUMBER(INFINEON_VID, INFINEON_TRIBOARD_PID, 1) },
        { }                                     /* Terminating entry */
index 1e58d90a0b6c974197de3d138cced219bf201a27..70b0b1d88ae9b383fde7f609015a9f0592797934 100644 (file)
@@ -42,6 +42,8 @@
 /* www.candapter.com Ewert Energy Systems CANdapter device */
 #define FTDI_CANDAPTER_PID 0x9F80 /* Product Id */
 
+#define FTDI_BM_ATOM_NANO_PID  0xa559  /* Basic Micro ATOM Nano USB2Serial */
+
 /*
  * Texas Instruments XDS100v2 JTAG / BeagleBone A3
  * http://processors.wiki.ti.com/index.php/XDS100
 #define BRAINBOXES_US_160_6_PID                0x9006 /* US-160 16xRS232 1Mbaud Port 11 and 12 */
 #define BRAINBOXES_US_160_7_PID                0x9007 /* US-160 16xRS232 1Mbaud Port 13 and 14 */
 #define BRAINBOXES_US_160_8_PID                0x9008 /* US-160 16xRS232 1Mbaud Port 15 and 16 */
+
+/*
+ * ekey biometric systems GmbH (http://ekey.net/)
+ */
+#define FTDI_EKEY_CONV_USB_PID         0xCB08  /* Converter USB */
index a9688940543d78d1724f28dae75a0929919e4f25..54a8120897a67f4783df9e3f525fb41359076734 100644 (file)
@@ -275,8 +275,12 @@ static void option_instat_callback(struct urb *urb);
 #define ZTE_PRODUCT_MF622                      0x0001
 #define ZTE_PRODUCT_MF628                      0x0015
 #define ZTE_PRODUCT_MF626                      0x0031
-#define ZTE_PRODUCT_MC2718                     0xffe8
 #define ZTE_PRODUCT_AC2726                     0xfff1
+#define ZTE_PRODUCT_CDMA_TECH                  0xfffe
+#define ZTE_PRODUCT_AC8710T                    0xffff
+#define ZTE_PRODUCT_MC2718                     0xffe8
+#define ZTE_PRODUCT_AD3812                     0xffeb
+#define ZTE_PRODUCT_MC2716                     0xffed
 
 #define BENQ_VENDOR_ID                         0x04a5
 #define BENQ_PRODUCT_H10                       0x4068
@@ -494,6 +498,10 @@ static void option_instat_callback(struct urb *urb);
 #define INOVIA_VENDOR_ID                       0x20a6
 #define INOVIA_SEW858                          0x1105
 
+/* VIA Telecom */
+#define VIATELECOM_VENDOR_ID                   0x15eb
+#define VIATELECOM_PRODUCT_CDS7                        0x0001
+
 /* some devices interfaces need special handling due to a number of reasons */
 enum option_blacklist_reason {
                OPTION_BLACKLIST_NONE = 0,
@@ -527,10 +535,18 @@ static const struct option_blacklist_info zte_k3765_z_blacklist = {
        .reserved = BIT(4),
 };
 
+static const struct option_blacklist_info zte_ad3812_z_blacklist = {
+       .sendsetup = BIT(0) | BIT(1) | BIT(2),
+};
+
 static const struct option_blacklist_info zte_mc2718_z_blacklist = {
        .sendsetup = BIT(1) | BIT(2) | BIT(3) | BIT(4),
 };
 
+static const struct option_blacklist_info zte_mc2716_z_blacklist = {
+       .sendsetup = BIT(1) | BIT(2) | BIT(3),
+};
+
 static const struct option_blacklist_info huawei_cdc12_blacklist = {
        .reserved = BIT(1) | BIT(2),
 };
@@ -1070,6 +1086,7 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_INTERFACE_CLASS(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1012, 0xff) },
        { USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC650) },
        { USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC680) },
+       { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6000)}, /* ZTE AC8700 */
        { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */
        { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x0023)}, /* ONYX 3G device */
        { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000)}, /* SIMCom SIM5218 */
@@ -1544,13 +1561,18 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff93, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff94, 0xff, 0xff, 0xff) },
 
-       /* NOTE: most ZTE CDMA devices should be driven by zte_ev, not option */
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_CDMA_TECH, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC2726, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710T, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MC2718, 0xff, 0xff, 0xff),
         .driver_info = (kernel_ulong_t)&zte_mc2718_z_blacklist },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AD3812, 0xff, 0xff, 0xff),
+        .driver_info = (kernel_ulong_t)&zte_ad3812_z_blacklist },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MC2716, 0xff, 0xff, 0xff),
+        .driver_info = (kernel_ulong_t)&zte_mc2716_z_blacklist },
        { USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x02, 0x01) },
        { USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x02, 0x05) },
        { USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x86, 0x10) },
-       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC2726, 0xff, 0xff, 0xff) },
 
        { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_H10) },
        { USB_DEVICE(DLINK_VENDOR_ID, DLINK_PRODUCT_DWM_652) },
@@ -1724,6 +1746,7 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e01, 0xff, 0xff, 0xff) }, /* D-Link DWM-152/C1 */
        { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e02, 0xff, 0xff, 0xff) }, /* D-Link DWM-156/C1 */
        { USB_DEVICE(INOVIA_VENDOR_ID, INOVIA_SEW858) },
+       { USB_DEVICE(VIATELECOM_VENDOR_ID, VIATELECOM_PRODUCT_CDS7) },
        { } /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, option_ids);
@@ -1916,6 +1939,8 @@ static void option_instat_callback(struct urb *urb)
                        dev_dbg(dev, "%s: type %x req %x\n", __func__,
                                req_pkt->bRequestType, req_pkt->bRequest);
                }
+       } else if (status == -ENOENT || status == -ESHUTDOWN) {
+               dev_dbg(dev, "%s: urb stopped: %d\n", __func__, status);
        } else
                dev_err(dev, "%s: error %d\n", __func__, status);
 
index b3d5a35c0d4b2e09ee3b0aea7fda1763d510c6a4..e9bad928039fd39ef00b73e898efa6a807e5b858 100644 (file)
@@ -45,6 +45,7 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) },
        { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_HCR331) },
        { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MOTOROLA) },
+       { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ZTEK) },
        { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
        { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
        { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
index 42bc082896ac8e9d8f913168a0f209a7bebb673e..71fd9da1d6e7ac6e36ecdf38e8f8192c60fbbc39 100644 (file)
@@ -22,6 +22,7 @@
 #define PL2303_PRODUCT_ID_GPRS         0x0609
 #define PL2303_PRODUCT_ID_HCR331       0x331a
 #define PL2303_PRODUCT_ID_MOTOROLA     0x0307
+#define PL2303_PRODUCT_ID_ZTEK         0xe1f1
 
 #define ATEN_VENDOR_ID         0x0557
 #define ATEN_VENDOR_ID2                0x0547
index 02de3110fe940e63308e7707a966c539bb620403..475723c006f955923d255be9abc408c7fd29027d 100644 (file)
@@ -764,29 +764,39 @@ static int usb_serial_probe(struct usb_interface *interface,
                if (usb_endpoint_is_bulk_in(endpoint)) {
                        /* we found a bulk in endpoint */
                        dev_dbg(ddev, "found bulk in on endpoint %d\n", i);
-                       bulk_in_endpoint[num_bulk_in] = endpoint;
-                       ++num_bulk_in;
+                       if (num_bulk_in < MAX_NUM_PORTS) {
+                               bulk_in_endpoint[num_bulk_in] = endpoint;
+                               ++num_bulk_in;
+                       }
                }
 
                if (usb_endpoint_is_bulk_out(endpoint)) {
                        /* we found a bulk out endpoint */
                        dev_dbg(ddev, "found bulk out on endpoint %d\n", i);
-                       bulk_out_endpoint[num_bulk_out] = endpoint;
-                       ++num_bulk_out;
+                       if (num_bulk_out < MAX_NUM_PORTS) {
+                               bulk_out_endpoint[num_bulk_out] = endpoint;
+                               ++num_bulk_out;
+                       }
                }
 
                if (usb_endpoint_is_int_in(endpoint)) {
                        /* we found a interrupt in endpoint */
                        dev_dbg(ddev, "found interrupt in on endpoint %d\n", i);
-                       interrupt_in_endpoint[num_interrupt_in] = endpoint;
-                       ++num_interrupt_in;
+                       if (num_interrupt_in < MAX_NUM_PORTS) {
+                               interrupt_in_endpoint[num_interrupt_in] =
+                                               endpoint;
+                               ++num_interrupt_in;
+                       }
                }
 
                if (usb_endpoint_is_int_out(endpoint)) {
                        /* we found an interrupt out endpoint */
                        dev_dbg(ddev, "found interrupt out on endpoint %d\n", i);
-                       interrupt_out_endpoint[num_interrupt_out] = endpoint;
-                       ++num_interrupt_out;
+                       if (num_interrupt_out < MAX_NUM_PORTS) {
+                               interrupt_out_endpoint[num_interrupt_out] =
+                                               endpoint;
+                               ++num_interrupt_out;
+                       }
                }
        }
 
@@ -809,8 +819,10 @@ static int usb_serial_probe(struct usb_interface *interface,
                                if (usb_endpoint_is_int_in(endpoint)) {
                                        /* we found a interrupt in endpoint */
                                        dev_dbg(ddev, "found interrupt in for Prolific device on separate interface\n");
-                                       interrupt_in_endpoint[num_interrupt_in] = endpoint;
-                                       ++num_interrupt_in;
+                                       if (num_interrupt_in < MAX_NUM_PORTS) {
+                                               interrupt_in_endpoint[num_interrupt_in] = endpoint;
+                                               ++num_interrupt_in;
+                                       }
                                }
                        }
                }
@@ -850,6 +862,11 @@ static int usb_serial_probe(struct usb_interface *interface,
                        num_ports = type->num_ports;
        }
 
+       if (num_ports > MAX_NUM_PORTS) {
+               dev_warn(ddev, "too many ports requested: %d\n", num_ports);
+               num_ports = MAX_NUM_PORTS;
+       }
+
        serial->num_ports = num_ports;
        serial->num_bulk_in = num_bulk_in;
        serial->num_bulk_out = num_bulk_out;
index e62f2dff8b7df6db65e684ef01dbbccced3a6066..6c3734d2b45a7a9ca24557a586ba10135b7cadb3 100644 (file)
@@ -514,6 +514,10 @@ static void command_port_read_callback(struct urb *urb)
                dev_dbg(&urb->dev->dev, "%s - command_info is NULL, exiting.\n", __func__);
                return;
        }
+       if (!urb->actual_length) {
+               dev_dbg(&urb->dev->dev, "%s - empty response, exiting.\n", __func__);
+               return;
+       }
        if (status) {
                dev_dbg(&urb->dev->dev, "%s - nonzero urb status: %d\n", __func__, status);
                if (status != -ENOENT)
@@ -534,7 +538,8 @@ static void command_port_read_callback(struct urb *urb)
                /* These are unsolicited reports from the firmware, hence no
                   waiting command to wakeup */
                dev_dbg(&urb->dev->dev, "%s - event received\n", __func__);
-       } else if (data[0] == WHITEHEAT_GET_DTR_RTS) {
+       } else if ((data[0] == WHITEHEAT_GET_DTR_RTS) &&
+               (urb->actual_length - 1 <= sizeof(command_info->result_buffer))) {
                memcpy(command_info->result_buffer, &data[1],
                                                urb->actual_length - 1);
                command_info->command_finished = WHITEHEAT_CMD_COMPLETE;
index e40ab739c4a6eb227f4704f75daee65a5f13f0be..1a132e9e947ac44ae7ac31554e39078f3cc122ca 100644 (file)
@@ -272,28 +272,8 @@ static void zte_ev_usb_serial_close(struct usb_serial_port *port)
 }
 
 static const struct usb_device_id id_table[] = {
-       /* AC8710, AC8710T */
-       { USB_DEVICE_AND_INTERFACE_INFO(0x19d2, 0xffff, 0xff, 0xff, 0xff) },
-        /* AC8700 */
-       { USB_DEVICE_AND_INTERFACE_INFO(0x19d2, 0xfffe, 0xff, 0xff, 0xff) },
        /* MG880 */
        { USB_DEVICE(0x19d2, 0xfffd) },
-       { USB_DEVICE(0x19d2, 0xfffc) },
-       { USB_DEVICE(0x19d2, 0xfffb) },
-       /* AC8710_V3 */
-       { USB_DEVICE(0x19d2, 0xfff6) },
-       { USB_DEVICE(0x19d2, 0xfff7) },
-       { USB_DEVICE(0x19d2, 0xfff8) },
-       { USB_DEVICE(0x19d2, 0xfff9) },
-       { USB_DEVICE(0x19d2, 0xffee) },
-       /* AC2716, MC2716 */
-       { USB_DEVICE_AND_INTERFACE_INFO(0x19d2, 0xffed, 0xff, 0xff, 0xff) },
-       /* AD3812 */
-       { USB_DEVICE_AND_INTERFACE_INFO(0x19d2, 0xffeb, 0xff, 0xff, 0xff) },
-       { USB_DEVICE(0x19d2, 0xffec) },
-       { USB_DEVICE(0x05C6, 0x3197) },
-       { USB_DEVICE(0x05C6, 0x6000) },
-       { USB_DEVICE(0x05C6, 0x9008) },
        { },
 };
 MODULE_DEVICE_TABLE(usb, id_table);
index 80a5b366255fb8acb812cadfe0ff6d63d5329ece..7ef99b2f3aaf75ff3222db35292ca3edaa7ac607 100644 (file)
@@ -922,6 +922,12 @@ UNUSUAL_DEV(  0x069b, 0x3004, 0x0001, 0x0001,
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
                US_FL_FIX_CAPACITY ),
 
+UNUSUAL_DEV(  0x06ca, 0x2003, 0x0100, 0x0100,
+               "Newer Technology",
+               "uSCSI",
+               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_euscsi_init,
+               US_FL_SCM_MULT_TARG ),
+
 /* Reported by Adrian Pilchowiec <adi1981@epf.pl> */
 UNUSUAL_DEV(  0x071b, 0x3203, 0x0000, 0x0000,
                "RockChip",
diff --git a/drivers/usb/usbip/Kconfig b/drivers/usb/usbip/Kconfig
new file mode 100644 (file)
index 0000000..bd99e9e
--- /dev/null
@@ -0,0 +1,41 @@
+config USBIP_CORE
+       tristate "USB/IP support"
+       depends on USB && NET
+       ---help---
+         This enables pushing USB packets over IP to allow remote
+         machines direct access to USB devices. It provides the
+         USB/IP core that is required by both drivers.
+
+         For more details, and to get the userspace utility
+         programs, please see <http://usbip.sourceforge.net/>.
+
+         To compile this as a module, choose M here: the module will
+         be called usbip-core.
+
+         If unsure, say N.
+
+config USBIP_VHCI_HCD
+       tristate "VHCI hcd"
+       depends on USBIP_CORE
+       ---help---
+         This enables the USB/IP virtual host controller driver,
+         which is run on the remote machine.
+
+         To compile this driver as a module, choose M here: the
+         module will be called vhci-hcd.
+
+config USBIP_HOST
+       tristate "Host driver"
+       depends on USBIP_CORE
+       ---help---
+         This enables the USB/IP host driver, which is run on the
+         machine that is sharing the USB devices.
+
+         To compile this driver as a module, choose M here: the
+         module will be called usbip-host.
+
+config USBIP_DEBUG
+       bool "Debug messages for USB/IP"
+       depends on USBIP_CORE
+       ---help---
+         This enables the debug messages from the USB/IP drivers.
diff --git a/drivers/usb/usbip/Makefile b/drivers/usb/usbip/Makefile
new file mode 100644 (file)
index 0000000..9ecd615
--- /dev/null
@@ -0,0 +1,10 @@
+ccflags-$(CONFIG_USBIP_DEBUG) := -DDEBUG
+
+obj-$(CONFIG_USBIP_CORE) += usbip-core.o
+usbip-core-y := usbip_common.o usbip_event.o
+
+obj-$(CONFIG_USBIP_VHCI_HCD) += vhci-hcd.o
+vhci-hcd-y := vhci_sysfs.o vhci_tx.o vhci_rx.o vhci_hcd.o
+
+obj-$(CONFIG_USBIP_HOST) += usbip-host.o
+usbip-host-y := stub_dev.o stub_main.o stub_rx.o stub_tx.o
diff --git a/drivers/usb/usbip/README b/drivers/usb/usbip/README
new file mode 100644 (file)
index 0000000..41a2cf2
--- /dev/null
@@ -0,0 +1,7 @@
+TODO:
+       - more discussion about the protocol
+       - testing
+       - review of the userspace interface
+       - document the protocol
+
+Please send patches for this code to Greg Kroah-Hartman <greg@kroah.com>
diff --git a/drivers/usb/usbip/stub.h b/drivers/usb/usbip/stub.h
new file mode 100644 (file)
index 0000000..266e2b0
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2003-2008 Takahiro Hirofuchi
+ *
+ * This 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 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 __USBIP_STUB_H
+#define __USBIP_STUB_H
+
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/usb.h>
+#include <linux/wait.h>
+
+#define STUB_BUSID_OTHER 0
+#define STUB_BUSID_REMOV 1
+#define STUB_BUSID_ADDED 2
+#define STUB_BUSID_ALLOC 3
+
+struct stub_device {
+       struct usb_interface *interface;
+       struct usb_device *udev;
+
+       struct usbip_device ud;
+       __u32 devid;
+
+       /*
+        * stub_priv preserves private data of each urb.
+        * It is allocated as stub_priv_cache and assigned to urb->context.
+        *
+        * stub_priv is always linked to any one of 3 lists;
+        *      priv_init: linked to this until the comletion of a urb.
+        *      priv_tx  : linked to this after the completion of a urb.
+        *      priv_free: linked to this after the sending of the result.
+        *
+        * Any of these list operations should be locked by priv_lock.
+        */
+       spinlock_t priv_lock;
+       struct list_head priv_init;
+       struct list_head priv_tx;
+       struct list_head priv_free;
+
+       /* see comments for unlinking in stub_rx.c */
+       struct list_head unlink_tx;
+       struct list_head unlink_free;
+
+       wait_queue_head_t tx_waitq;
+};
+
+/* private data into urb->priv */
+struct stub_priv {
+       unsigned long seqnum;
+       struct list_head list;
+       struct stub_device *sdev;
+       struct urb *urb;
+
+       int unlinking;
+};
+
+struct stub_unlink {
+       unsigned long seqnum;
+       struct list_head list;
+       __u32 status;
+};
+
+/* same as SYSFS_BUS_ID_SIZE */
+#define BUSID_SIZE 32
+
+struct bus_id_priv {
+       char name[BUSID_SIZE];
+       char status;
+       int interf_count;
+       struct stub_device *sdev;
+       struct usb_device *udev;
+       char shutdown_busid;
+};
+
+/* stub_priv is allocated from stub_priv_cache */
+extern struct kmem_cache *stub_priv_cache;
+
+/* stub_dev.c */
+extern struct usb_device_driver stub_driver;
+
+/* stub_main.c */
+struct bus_id_priv *get_busid_priv(const char *busid);
+int del_match_busid(char *busid);
+void stub_device_cleanup_urbs(struct stub_device *sdev);
+
+/* stub_rx.c */
+int stub_rx_loop(void *data);
+
+/* stub_tx.c */
+void stub_enqueue_ret_unlink(struct stub_device *sdev, __u32 seqnum,
+                            __u32 status);
+void stub_complete(struct urb *urb);
+int stub_tx_loop(void *data);
+
+#endif /* __USBIP_STUB_H */
diff --git a/drivers/usb/usbip/stub_dev.c b/drivers/usb/usbip/stub_dev.c
new file mode 100644 (file)
index 0000000..fac20e0
--- /dev/null
@@ -0,0 +1,498 @@
+/*
+ * Copyright (C) 2003-2008 Takahiro Hirofuchi
+ *
+ * This 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 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/device.h>
+#include <linux/file.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+
+#include "usbip_common.h"
+#include "stub.h"
+
+/*
+ * usbip_status shows the status of usbip-host as long as this driver is bound
+ * to the target device.
+ */
+static ssize_t usbip_status_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       struct stub_device *sdev = dev_get_drvdata(dev);
+       int status;
+
+       if (!sdev) {
+               dev_err(dev, "sdev is null\n");
+               return -ENODEV;
+       }
+
+       spin_lock_irq(&sdev->ud.lock);
+       status = sdev->ud.status;
+       spin_unlock_irq(&sdev->ud.lock);
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", status);
+}
+static DEVICE_ATTR_RO(usbip_status);
+
+/*
+ * usbip_sockfd gets a socket descriptor of an established TCP connection that
+ * is used to transfer usbip requests by kernel threads. -1 is a magic number
+ * by which usbip connection is finished.
+ */
+static ssize_t store_sockfd(struct device *dev, struct device_attribute *attr,
+                           const char *buf, size_t count)
+{
+       struct stub_device *sdev = dev_get_drvdata(dev);
+       int sockfd = 0;
+       struct socket *socket;
+       int rv;
+
+       if (!sdev) {
+               dev_err(dev, "sdev is null\n");
+               return -ENODEV;
+       }
+
+       rv = sscanf(buf, "%d", &sockfd);
+       if (rv != 1)
+               return -EINVAL;
+
+       if (sockfd != -1) {
+               int err;
+
+               dev_info(dev, "stub up\n");
+
+               spin_lock_irq(&sdev->ud.lock);
+
+               if (sdev->ud.status != SDEV_ST_AVAILABLE) {
+                       dev_err(dev, "not ready\n");
+                       goto err;
+               }
+
+               socket = sockfd_lookup(sockfd, &err);
+               if (!socket)
+                       goto err;
+
+               sdev->ud.tcp_socket = socket;
+
+               spin_unlock_irq(&sdev->ud.lock);
+
+               sdev->ud.tcp_rx = kthread_get_run(stub_rx_loop, &sdev->ud,
+                                                 "stub_rx");
+               sdev->ud.tcp_tx = kthread_get_run(stub_tx_loop, &sdev->ud,
+                                                 "stub_tx");
+
+               spin_lock_irq(&sdev->ud.lock);
+               sdev->ud.status = SDEV_ST_USED;
+               spin_unlock_irq(&sdev->ud.lock);
+
+       } else {
+               dev_info(dev, "stub down\n");
+
+               spin_lock_irq(&sdev->ud.lock);
+               if (sdev->ud.status != SDEV_ST_USED)
+                       goto err;
+
+               spin_unlock_irq(&sdev->ud.lock);
+
+               usbip_event_add(&sdev->ud, SDEV_EVENT_DOWN);
+       }
+
+       return count;
+
+err:
+       spin_unlock_irq(&sdev->ud.lock);
+       return -EINVAL;
+}
+static DEVICE_ATTR(usbip_sockfd, S_IWUSR, NULL, store_sockfd);
+
+static int stub_add_files(struct device *dev)
+{
+       int err = 0;
+
+       err = device_create_file(dev, &dev_attr_usbip_status);
+       if (err)
+               goto err_status;
+
+       err = device_create_file(dev, &dev_attr_usbip_sockfd);
+       if (err)
+               goto err_sockfd;
+
+       err = device_create_file(dev, &dev_attr_usbip_debug);
+       if (err)
+               goto err_debug;
+
+       return 0;
+
+err_debug:
+       device_remove_file(dev, &dev_attr_usbip_sockfd);
+err_sockfd:
+       device_remove_file(dev, &dev_attr_usbip_status);
+err_status:
+       return err;
+}
+
+static void stub_remove_files(struct device *dev)
+{
+       device_remove_file(dev, &dev_attr_usbip_status);
+       device_remove_file(dev, &dev_attr_usbip_sockfd);
+       device_remove_file(dev, &dev_attr_usbip_debug);
+}
+
+static void stub_shutdown_connection(struct usbip_device *ud)
+{
+       struct stub_device *sdev = container_of(ud, struct stub_device, ud);
+
+       /*
+        * When removing an exported device, kernel panic sometimes occurred
+        * and then EIP was sk_wait_data of stub_rx thread. Is this because
+        * sk_wait_data returned though stub_rx thread was already finished by
+        * step 1?
+        */
+       if (ud->tcp_socket) {
+               dev_dbg(&sdev->udev->dev, "shutdown tcp_socket %p\n",
+                       ud->tcp_socket);
+               kernel_sock_shutdown(ud->tcp_socket, SHUT_RDWR);
+       }
+
+       /* 1. stop threads */
+       if (ud->tcp_rx) {
+               kthread_stop_put(ud->tcp_rx);
+               ud->tcp_rx = NULL;
+       }
+       if (ud->tcp_tx) {
+               kthread_stop_put(ud->tcp_tx);
+               ud->tcp_tx = NULL;
+       }
+
+       /*
+        * 2. close the socket
+        *
+        * tcp_socket is freed after threads are killed so that usbip_xmit does
+        * not touch NULL socket.
+        */
+       if (ud->tcp_socket) {
+               sockfd_put(ud->tcp_socket);
+               ud->tcp_socket = NULL;
+       }
+
+       /* 3. free used data */
+       stub_device_cleanup_urbs(sdev);
+
+       /* 4. free stub_unlink */
+       {
+               unsigned long flags;
+               struct stub_unlink *unlink, *tmp;
+
+               spin_lock_irqsave(&sdev->priv_lock, flags);
+               list_for_each_entry_safe(unlink, tmp, &sdev->unlink_tx, list) {
+                       list_del(&unlink->list);
+                       kfree(unlink);
+               }
+               list_for_each_entry_safe(unlink, tmp, &sdev->unlink_free,
+                                        list) {
+                       list_del(&unlink->list);
+                       kfree(unlink);
+               }
+               spin_unlock_irqrestore(&sdev->priv_lock, flags);
+       }
+}
+
+static void stub_device_reset(struct usbip_device *ud)
+{
+       struct stub_device *sdev = container_of(ud, struct stub_device, ud);
+       struct usb_device *udev = sdev->udev;
+       int ret;
+
+       dev_dbg(&udev->dev, "device reset");
+
+       ret = usb_lock_device_for_reset(udev, sdev->interface);
+       if (ret < 0) {
+               dev_err(&udev->dev, "lock for reset\n");
+               spin_lock_irq(&ud->lock);
+               ud->status = SDEV_ST_ERROR;
+               spin_unlock_irq(&ud->lock);
+               return;
+       }
+
+       /* try to reset the device */
+       ret = usb_reset_device(udev);
+       usb_unlock_device(udev);
+
+       spin_lock_irq(&ud->lock);
+       if (ret) {
+               dev_err(&udev->dev, "device reset\n");
+               ud->status = SDEV_ST_ERROR;
+       } else {
+               dev_info(&udev->dev, "device reset\n");
+               ud->status = SDEV_ST_AVAILABLE;
+       }
+       spin_unlock_irq(&ud->lock);
+}
+
+static void stub_device_unusable(struct usbip_device *ud)
+{
+       spin_lock_irq(&ud->lock);
+       ud->status = SDEV_ST_ERROR;
+       spin_unlock_irq(&ud->lock);
+}
+
+/**
+ * stub_device_alloc - allocate a new stub_device struct
+ * @interface: usb_interface of a new device
+ *
+ * Allocates and initializes a new stub_device struct.
+ */
+static struct stub_device *stub_device_alloc(struct usb_device *udev)
+{
+       struct stub_device *sdev;
+       int busnum = udev->bus->busnum;
+       int devnum = udev->devnum;
+
+       dev_dbg(&udev->dev, "allocating stub device");
+
+       /* yes, it's a new device */
+       sdev = kzalloc(sizeof(struct stub_device), GFP_KERNEL);
+       if (!sdev)
+               return NULL;
+
+       sdev->udev = usb_get_dev(udev);
+
+       /*
+        * devid is defined with devnum when this driver is first allocated.
+        * devnum may change later if a device is reset. However, devid never
+        * changes during a usbip connection.
+        */
+       sdev->devid             = (busnum << 16) | devnum;
+       sdev->ud.side           = USBIP_STUB;
+       sdev->ud.status         = SDEV_ST_AVAILABLE;
+       spin_lock_init(&sdev->ud.lock);
+       sdev->ud.tcp_socket     = NULL;
+
+       INIT_LIST_HEAD(&sdev->priv_init);
+       INIT_LIST_HEAD(&sdev->priv_tx);
+       INIT_LIST_HEAD(&sdev->priv_free);
+       INIT_LIST_HEAD(&sdev->unlink_free);
+       INIT_LIST_HEAD(&sdev->unlink_tx);
+       spin_lock_init(&sdev->priv_lock);
+
+       init_waitqueue_head(&sdev->tx_waitq);
+
+       sdev->ud.eh_ops.shutdown = stub_shutdown_connection;
+       sdev->ud.eh_ops.reset    = stub_device_reset;
+       sdev->ud.eh_ops.unusable = stub_device_unusable;
+
+       usbip_start_eh(&sdev->ud);
+
+       dev_dbg(&udev->dev, "register new device\n");
+
+       return sdev;
+}
+
+static void stub_device_free(struct stub_device *sdev)
+{
+       kfree(sdev);
+}
+
+static int stub_probe(struct usb_device *udev)
+{
+       struct stub_device *sdev = NULL;
+       const char *udev_busid = dev_name(&udev->dev);
+       int err = 0;
+       struct bus_id_priv *busid_priv;
+       int rc;
+
+       dev_dbg(&udev->dev, "Enter\n");
+
+       /* check we should claim or not by busid_table */
+       busid_priv = get_busid_priv(udev_busid);
+       if (!busid_priv || (busid_priv->status == STUB_BUSID_REMOV) ||
+           (busid_priv->status == STUB_BUSID_OTHER)) {
+               dev_info(&udev->dev,
+                       "%s is not in match_busid table... skip!\n",
+                       udev_busid);
+
+               /*
+                * Return value should be ENODEV or ENOXIO to continue trying
+                * other matched drivers by the driver core.
+                * See driver_probe_device() in driver/base/dd.c
+                */
+               return -ENODEV;
+       }
+
+       if (udev->descriptor.bDeviceClass == USB_CLASS_HUB) {
+               dev_dbg(&udev->dev, "%s is a usb hub device... skip!\n",
+                        udev_busid);
+               return -ENODEV;
+       }
+
+       if (!strcmp(udev->bus->bus_name, "vhci_hcd")) {
+               dev_dbg(&udev->dev,
+                       "%s is attached on vhci_hcd... skip!\n",
+                       udev_busid);
+
+               return -ENODEV;
+       }
+
+       /* ok, this is my device */
+       sdev = stub_device_alloc(udev);
+       if (!sdev)
+               return -ENOMEM;
+
+       dev_info(&udev->dev,
+               "usbip-host: register new device (bus %u dev %u)\n",
+               udev->bus->busnum, udev->devnum);
+
+       busid_priv->shutdown_busid = 0;
+
+       /* set private data to usb_device */
+       dev_set_drvdata(&udev->dev, sdev);
+       busid_priv->sdev = sdev;
+       busid_priv->udev = udev;
+
+       /*
+        * Claim this hub port.
+        * It doesn't matter what value we pass as owner
+        * (struct dev_state) as long as it is unique.
+        */
+       rc = usb_hub_claim_port(udev->parent, udev->portnum,
+                       (struct usb_dev_state *) udev);
+       if (rc) {
+               dev_dbg(&udev->dev, "unable to claim port\n");
+               return rc;
+       }
+
+       err = stub_add_files(&udev->dev);
+       if (err) {
+               dev_err(&udev->dev, "stub_add_files for %s\n", udev_busid);
+               dev_set_drvdata(&udev->dev, NULL);
+               usb_put_dev(udev);
+               kthread_stop_put(sdev->ud.eh);
+
+               busid_priv->sdev = NULL;
+               stub_device_free(sdev);
+               return err;
+       }
+       busid_priv->status = STUB_BUSID_ALLOC;
+
+       return 0;
+}
+
+static void shutdown_busid(struct bus_id_priv *busid_priv)
+{
+       if (busid_priv->sdev && !busid_priv->shutdown_busid) {
+               busid_priv->shutdown_busid = 1;
+               usbip_event_add(&busid_priv->sdev->ud, SDEV_EVENT_REMOVED);
+
+               /* wait for the stop of the event handler */
+               usbip_stop_eh(&busid_priv->sdev->ud);
+       }
+}
+
+/*
+ * called in usb_disconnect() or usb_deregister()
+ * but only if actconfig(active configuration) exists
+ */
+static void stub_disconnect(struct usb_device *udev)
+{
+       struct stub_device *sdev;
+       const char *udev_busid = dev_name(&udev->dev);
+       struct bus_id_priv *busid_priv;
+       int rc;
+
+       dev_dbg(&udev->dev, "Enter\n");
+
+       busid_priv = get_busid_priv(udev_busid);
+       if (!busid_priv) {
+               BUG();
+               return;
+       }
+
+       sdev = dev_get_drvdata(&udev->dev);
+
+       /* get stub_device */
+       if (!sdev) {
+               dev_err(&udev->dev, "could not get device");
+               return;
+       }
+
+       dev_set_drvdata(&udev->dev, NULL);
+
+       /*
+        * NOTE: rx/tx threads are invoked for each usb_device.
+        */
+       stub_remove_files(&udev->dev);
+
+       /* release port */
+       rc = usb_hub_release_port(udev->parent, udev->portnum,
+                                 (struct usb_dev_state *) udev);
+       if (rc) {
+               dev_dbg(&udev->dev, "unable to release port\n");
+               return;
+       }
+
+       /* If usb reset is called from event handler */
+       if (busid_priv->sdev->ud.eh == current)
+               return;
+
+       /* shutdown the current connection */
+       shutdown_busid(busid_priv);
+
+       usb_put_dev(sdev->udev);
+
+       /* free sdev */
+       busid_priv->sdev = NULL;
+       stub_device_free(sdev);
+
+       if (busid_priv->status == STUB_BUSID_ALLOC) {
+               busid_priv->status = STUB_BUSID_ADDED;
+       } else {
+               busid_priv->status = STUB_BUSID_OTHER;
+               del_match_busid((char *)udev_busid);
+       }
+}
+
+#ifdef CONFIG_PM
+
+/* These functions need usb_port_suspend and usb_port_resume,
+ * which reside in drivers/usb/core/usb.h. Skip for now. */
+
+static int stub_suspend(struct usb_device *udev, pm_message_t message)
+{
+       dev_dbg(&udev->dev, "stub_suspend\n");
+
+       return 0;
+}
+
+static int stub_resume(struct usb_device *udev, pm_message_t message)
+{
+       dev_dbg(&udev->dev, "stub_resume\n");
+
+       return 0;
+}
+
+#endif /* CONFIG_PM */
+
+struct usb_device_driver stub_driver = {
+       .name           = "usbip-host",
+       .probe          = stub_probe,
+       .disconnect     = stub_disconnect,
+#ifdef CONFIG_PM
+       .suspend        = stub_suspend,
+       .resume         = stub_resume,
+#endif
+       .supports_autosuspend   =       0,
+};
diff --git a/drivers/usb/usbip/stub_main.c b/drivers/usb/usbip/stub_main.c
new file mode 100644 (file)
index 0000000..44ab43f
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 2003-2008 Takahiro Hirofuchi
+ *
+ * This 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 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/string.h>
+#include <linux/module.h>
+#include <linux/device.h>
+
+#include "usbip_common.h"
+#include "stub.h"
+
+#define DRIVER_AUTHOR "Takahiro Hirofuchi"
+#define DRIVER_DESC "USB/IP Host Driver"
+
+struct kmem_cache *stub_priv_cache;
+/*
+ * busid_tables defines matching busids that usbip can grab. A user can change
+ * dynamically what device is locally used and what device is exported to a
+ * remote host.
+ */
+#define MAX_BUSID 16
+static struct bus_id_priv busid_table[MAX_BUSID];
+static spinlock_t busid_table_lock;
+
+static void init_busid_table(void)
+{
+       /*
+        * This also sets the bus_table[i].status to
+        * STUB_BUSID_OTHER, which is 0.
+        */
+       memset(busid_table, 0, sizeof(busid_table));
+
+       spin_lock_init(&busid_table_lock);
+}
+
+/*
+ * Find the index of the busid by name.
+ * Must be called with busid_table_lock held.
+ */
+static int get_busid_idx(const char *busid)
+{
+       int i;
+       int idx = -1;
+
+       for (i = 0; i < MAX_BUSID; i++)
+               if (busid_table[i].name[0])
+                       if (!strncmp(busid_table[i].name, busid, BUSID_SIZE)) {
+                               idx = i;
+                               break;
+                       }
+       return idx;
+}
+
+struct bus_id_priv *get_busid_priv(const char *busid)
+{
+       int idx;
+       struct bus_id_priv *bid = NULL;
+
+       spin_lock(&busid_table_lock);
+       idx = get_busid_idx(busid);
+       if (idx >= 0)
+               bid = &(busid_table[idx]);
+       spin_unlock(&busid_table_lock);
+
+       return bid;
+}
+
+static int add_match_busid(char *busid)
+{
+       int i;
+       int ret = -1;
+
+       spin_lock(&busid_table_lock);
+       /* already registered? */
+       if (get_busid_idx(busid) >= 0) {
+               ret = 0;
+               goto out;
+       }
+
+       for (i = 0; i < MAX_BUSID; i++)
+               if (!busid_table[i].name[0]) {
+                       strlcpy(busid_table[i].name, busid, BUSID_SIZE);
+                       if ((busid_table[i].status != STUB_BUSID_ALLOC) &&
+                           (busid_table[i].status != STUB_BUSID_REMOV))
+                               busid_table[i].status = STUB_BUSID_ADDED;
+                       ret = 0;
+                       break;
+               }
+
+out:
+       spin_unlock(&busid_table_lock);
+
+       return ret;
+}
+
+int del_match_busid(char *busid)
+{
+       int idx;
+       int ret = -1;
+
+       spin_lock(&busid_table_lock);
+       idx = get_busid_idx(busid);
+       if (idx < 0)
+               goto out;
+
+       /* found */
+       ret = 0;
+
+       if (busid_table[idx].status == STUB_BUSID_OTHER)
+               memset(busid_table[idx].name, 0, BUSID_SIZE);
+
+       if ((busid_table[idx].status != STUB_BUSID_OTHER) &&
+           (busid_table[idx].status != STUB_BUSID_ADDED))
+               busid_table[idx].status = STUB_BUSID_REMOV;
+
+out:
+       spin_unlock(&busid_table_lock);
+
+       return ret;
+}
+
+static ssize_t show_match_busid(struct device_driver *drv, char *buf)
+{
+       int i;
+       char *out = buf;
+
+       spin_lock(&busid_table_lock);
+       for (i = 0; i < MAX_BUSID; i++)
+               if (busid_table[i].name[0])
+                       out += sprintf(out, "%s ", busid_table[i].name);
+       spin_unlock(&busid_table_lock);
+       out += sprintf(out, "\n");
+
+       return out - buf;
+}
+
+static ssize_t store_match_busid(struct device_driver *dev, const char *buf,
+                                size_t count)
+{
+       int len;
+       char busid[BUSID_SIZE];
+
+       if (count < 5)
+               return -EINVAL;
+
+       /* busid needs to include \0 termination */
+       len = strlcpy(busid, buf + 4, BUSID_SIZE);
+       if (sizeof(busid) <= len)
+               return -EINVAL;
+
+       if (!strncmp(buf, "add ", 4)) {
+               if (add_match_busid(busid) < 0)
+                       return -ENOMEM;
+
+               pr_debug("add busid %s\n", busid);
+               return count;
+       }
+
+       if (!strncmp(buf, "del ", 4)) {
+               if (del_match_busid(busid) < 0)
+                       return -ENODEV;
+
+               pr_debug("del busid %s\n", busid);
+               return count;
+       }
+
+       return -EINVAL;
+}
+static DRIVER_ATTR(match_busid, S_IRUSR | S_IWUSR, show_match_busid,
+                  store_match_busid);
+
+static ssize_t rebind_store(struct device_driver *dev, const char *buf,
+                                size_t count)
+{
+       int ret;
+       int len;
+       struct bus_id_priv *bid;
+
+       /* buf length should be less that BUSID_SIZE */
+       len = strnlen(buf, BUSID_SIZE);
+
+       if (!(len < BUSID_SIZE))
+               return -EINVAL;
+
+       bid = get_busid_priv(buf);
+       if (!bid)
+               return -ENODEV;
+
+       ret = device_attach(&bid->udev->dev);
+       if (ret < 0) {
+               dev_err(&bid->udev->dev, "rebind failed\n");
+               return ret;
+       }
+
+       return count;
+}
+
+static DRIVER_ATTR_WO(rebind);
+
+static struct stub_priv *stub_priv_pop_from_listhead(struct list_head *listhead)
+{
+       struct stub_priv *priv, *tmp;
+
+       list_for_each_entry_safe(priv, tmp, listhead, list) {
+               list_del(&priv->list);
+               return priv;
+       }
+
+       return NULL;
+}
+
+static struct stub_priv *stub_priv_pop(struct stub_device *sdev)
+{
+       unsigned long flags;
+       struct stub_priv *priv;
+
+       spin_lock_irqsave(&sdev->priv_lock, flags);
+
+       priv = stub_priv_pop_from_listhead(&sdev->priv_init);
+       if (priv)
+               goto done;
+
+       priv = stub_priv_pop_from_listhead(&sdev->priv_tx);
+       if (priv)
+               goto done;
+
+       priv = stub_priv_pop_from_listhead(&sdev->priv_free);
+
+done:
+       spin_unlock_irqrestore(&sdev->priv_lock, flags);
+
+       return priv;
+}
+
+void stub_device_cleanup_urbs(struct stub_device *sdev)
+{
+       struct stub_priv *priv;
+       struct urb *urb;
+
+       dev_dbg(&sdev->udev->dev, "free sdev %p\n", sdev);
+
+       while ((priv = stub_priv_pop(sdev))) {
+               urb = priv->urb;
+               dev_dbg(&sdev->udev->dev, "free urb %p\n", urb);
+               usb_kill_urb(urb);
+
+               kmem_cache_free(stub_priv_cache, priv);
+
+               kfree(urb->transfer_buffer);
+               kfree(urb->setup_packet);
+               usb_free_urb(urb);
+       }
+}
+
+static int __init usbip_host_init(void)
+{
+       int ret;
+
+       init_busid_table();
+
+       stub_priv_cache = KMEM_CACHE(stub_priv, SLAB_HWCACHE_ALIGN);
+       if (!stub_priv_cache) {
+               pr_err("kmem_cache_create failed\n");
+               return -ENOMEM;
+       }
+
+       ret = usb_register_device_driver(&stub_driver, THIS_MODULE);
+       if (ret) {
+               pr_err("usb_register failed %d\n", ret);
+               goto err_usb_register;
+       }
+
+       ret = driver_create_file(&stub_driver.drvwrap.driver,
+                                &driver_attr_match_busid);
+       if (ret) {
+               pr_err("driver_create_file failed\n");
+               goto err_create_file;
+       }
+
+       ret = driver_create_file(&stub_driver.drvwrap.driver,
+                                &driver_attr_rebind);
+       if (ret) {
+               pr_err("driver_create_file failed\n");
+               goto err_create_file;
+       }
+
+       pr_info(DRIVER_DESC " v" USBIP_VERSION "\n");
+       return ret;
+
+err_create_file:
+       usb_deregister_device_driver(&stub_driver);
+err_usb_register:
+       kmem_cache_destroy(stub_priv_cache);
+       return ret;
+}
+
+static void __exit usbip_host_exit(void)
+{
+       driver_remove_file(&stub_driver.drvwrap.driver,
+                          &driver_attr_match_busid);
+
+       driver_remove_file(&stub_driver.drvwrap.driver,
+                          &driver_attr_rebind);
+
+       /*
+        * deregister() calls stub_disconnect() for all devices. Device
+        * specific data is cleared in stub_disconnect().
+        */
+       usb_deregister_device_driver(&stub_driver);
+
+       kmem_cache_destroy(stub_priv_cache);
+}
+
+module_init(usbip_host_init);
+module_exit(usbip_host_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_VERSION(USBIP_VERSION);
diff --git a/drivers/usb/usbip/stub_rx.c b/drivers/usb/usbip/stub_rx.c
new file mode 100644 (file)
index 0000000..00e475c
--- /dev/null
@@ -0,0 +1,594 @@
+/*
+ * Copyright (C) 2003-2008 Takahiro Hirofuchi
+ *
+ * This 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 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 <asm/byteorder.h>
+#include <linux/kthread.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+
+#include "usbip_common.h"
+#include "stub.h"
+
+static int is_clear_halt_cmd(struct urb *urb)
+{
+       struct usb_ctrlrequest *req;
+
+       req = (struct usb_ctrlrequest *) urb->setup_packet;
+
+        return (req->bRequest == USB_REQ_CLEAR_FEATURE) &&
+                (req->bRequestType == USB_RECIP_ENDPOINT) &&
+                (req->wValue == USB_ENDPOINT_HALT);
+}
+
+static int is_set_interface_cmd(struct urb *urb)
+{
+       struct usb_ctrlrequest *req;
+
+       req = (struct usb_ctrlrequest *) urb->setup_packet;
+
+       return (req->bRequest == USB_REQ_SET_INTERFACE) &&
+               (req->bRequestType == USB_RECIP_INTERFACE);
+}
+
+static int is_set_configuration_cmd(struct urb *urb)
+{
+       struct usb_ctrlrequest *req;
+
+       req = (struct usb_ctrlrequest *) urb->setup_packet;
+
+       return (req->bRequest == USB_REQ_SET_CONFIGURATION) &&
+               (req->bRequestType == USB_RECIP_DEVICE);
+}
+
+static int is_reset_device_cmd(struct urb *urb)
+{
+       struct usb_ctrlrequest *req;
+       __u16 value;
+       __u16 index;
+
+       req = (struct usb_ctrlrequest *) urb->setup_packet;
+       value = le16_to_cpu(req->wValue);
+       index = le16_to_cpu(req->wIndex);
+
+       if ((req->bRequest == USB_REQ_SET_FEATURE) &&
+           (req->bRequestType == USB_RT_PORT) &&
+           (value == USB_PORT_FEAT_RESET)) {
+               usbip_dbg_stub_rx("reset_device_cmd, port %u\n", index);
+               return 1;
+       } else
+               return 0;
+}
+
+static int tweak_clear_halt_cmd(struct urb *urb)
+{
+       struct usb_ctrlrequest *req;
+       int target_endp;
+       int target_dir;
+       int target_pipe;
+       int ret;
+
+       req = (struct usb_ctrlrequest *) urb->setup_packet;
+
+       /*
+        * The stalled endpoint is specified in the wIndex value. The endpoint
+        * of the urb is the target of this clear_halt request (i.e., control
+        * endpoint).
+        */
+       target_endp = le16_to_cpu(req->wIndex) & 0x000f;
+
+       /* the stalled endpoint direction is IN or OUT?. USB_DIR_IN is 0x80.  */
+       target_dir = le16_to_cpu(req->wIndex) & 0x0080;
+
+       if (target_dir)
+               target_pipe = usb_rcvctrlpipe(urb->dev, target_endp);
+       else
+               target_pipe = usb_sndctrlpipe(urb->dev, target_endp);
+
+       ret = usb_clear_halt(urb->dev, target_pipe);
+       if (ret < 0)
+               dev_err(&urb->dev->dev,
+                       "usb_clear_halt error: devnum %d endp %d ret %d\n",
+                       urb->dev->devnum, target_endp, ret);
+       else
+               dev_info(&urb->dev->dev,
+                        "usb_clear_halt done: devnum %d endp %d\n",
+                        urb->dev->devnum, target_endp);
+
+       return ret;
+}
+
+static int tweak_set_interface_cmd(struct urb *urb)
+{
+       struct usb_ctrlrequest *req;
+       __u16 alternate;
+       __u16 interface;
+       int ret;
+
+       req = (struct usb_ctrlrequest *) urb->setup_packet;
+       alternate = le16_to_cpu(req->wValue);
+       interface = le16_to_cpu(req->wIndex);
+
+       usbip_dbg_stub_rx("set_interface: inf %u alt %u\n",
+                         interface, alternate);
+
+       ret = usb_set_interface(urb->dev, interface, alternate);
+       if (ret < 0)
+               dev_err(&urb->dev->dev,
+                       "usb_set_interface error: inf %u alt %u ret %d\n",
+                       interface, alternate, ret);
+       else
+               dev_info(&urb->dev->dev,
+                       "usb_set_interface done: inf %u alt %u\n",
+                       interface, alternate);
+
+       return ret;
+}
+
+static int tweak_set_configuration_cmd(struct urb *urb)
+{
+       struct stub_priv *priv = (struct stub_priv *) urb->context;
+       struct stub_device *sdev = priv->sdev;
+       struct usb_ctrlrequest *req;
+       __u16 config;
+       int err;
+
+       req = (struct usb_ctrlrequest *) urb->setup_packet;
+       config = le16_to_cpu(req->wValue);
+
+       err = usb_set_configuration(sdev->udev, config);
+       if (err && err != -ENODEV)
+               dev_err(&sdev->udev->dev, "can't set config #%d, error %d\n",
+                       config, err);
+       return 0;
+}
+
+static int tweak_reset_device_cmd(struct urb *urb)
+{
+       struct stub_priv *priv = (struct stub_priv *) urb->context;
+       struct stub_device *sdev = priv->sdev;
+
+       dev_info(&urb->dev->dev, "usb_queue_reset_device\n");
+
+       /*
+        * With the implementation of pre_reset and post_reset the driver no
+        * longer unbinds. This allows the use of synchronous reset.
+        */
+
+       if (usb_lock_device_for_reset(sdev->udev, sdev->interface) < 0) {
+               dev_err(&urb->dev->dev, "could not obtain lock to reset device\n");
+               return 0;
+       }
+       usb_reset_device(sdev->udev);
+       usb_unlock_device(sdev->udev);
+
+       return 0;
+}
+
+/*
+ * clear_halt, set_interface, and set_configuration require special tricks.
+ */
+static void tweak_special_requests(struct urb *urb)
+{
+       if (!urb || !urb->setup_packet)
+               return;
+
+       if (usb_pipetype(urb->pipe) != PIPE_CONTROL)
+               return;
+
+       if (is_clear_halt_cmd(urb))
+               /* tweak clear_halt */
+                tweak_clear_halt_cmd(urb);
+
+       else if (is_set_interface_cmd(urb))
+               /* tweak set_interface */
+               tweak_set_interface_cmd(urb);
+
+       else if (is_set_configuration_cmd(urb))
+               /* tweak set_configuration */
+               tweak_set_configuration_cmd(urb);
+
+       else if (is_reset_device_cmd(urb))
+               tweak_reset_device_cmd(urb);
+       else
+               usbip_dbg_stub_rx("no need to tweak\n");
+}
+
+/*
+ * stub_recv_unlink() unlinks the URB by a call to usb_unlink_urb().
+ * By unlinking the urb asynchronously, stub_rx can continuously
+ * process coming urbs.  Even if the urb is unlinked, its completion
+ * handler will be called and stub_tx will send a return pdu.
+ *
+ * See also comments about unlinking strategy in vhci_hcd.c.
+ */
+static int stub_recv_cmd_unlink(struct stub_device *sdev,
+                               struct usbip_header *pdu)
+{
+       int ret;
+       unsigned long flags;
+       struct stub_priv *priv;
+
+       spin_lock_irqsave(&sdev->priv_lock, flags);
+
+       list_for_each_entry(priv, &sdev->priv_init, list) {
+               if (priv->seqnum != pdu->u.cmd_unlink.seqnum)
+                       continue;
+
+               dev_info(&priv->urb->dev->dev, "unlink urb %p\n",
+                        priv->urb);
+
+               /*
+                * This matched urb is not completed yet (i.e., be in
+                * flight in usb hcd hardware/driver). Now we are
+                * cancelling it. The unlinking flag means that we are
+                * now not going to return the normal result pdu of a
+                * submission request, but going to return a result pdu
+                * of the unlink request.
+                */
+               priv->unlinking = 1;
+
+               /*
+                * In the case that unlinking flag is on, prev->seqnum
+                * is changed from the seqnum of the cancelling urb to
+                * the seqnum of the unlink request. This will be used
+                * to make the result pdu of the unlink request.
+                */
+               priv->seqnum = pdu->base.seqnum;
+
+               spin_unlock_irqrestore(&sdev->priv_lock, flags);
+
+               /*
+                * usb_unlink_urb() is now out of spinlocking to avoid
+                * spinlock recursion since stub_complete() is
+                * sometimes called in this context but not in the
+                * interrupt context.  If stub_complete() is executed
+                * before we call usb_unlink_urb(), usb_unlink_urb()
+                * will return an error value. In this case, stub_tx
+                * will return the result pdu of this unlink request
+                * though submission is completed and actual unlinking
+                * is not executed. OK?
+                */
+               /* In the above case, urb->status is not -ECONNRESET,
+                * so a driver in a client host will know the failure
+                * of the unlink request ?
+                */
+               ret = usb_unlink_urb(priv->urb);
+               if (ret != -EINPROGRESS)
+                       dev_err(&priv->urb->dev->dev,
+                               "failed to unlink a urb %p, ret %d\n",
+                               priv->urb, ret);
+
+               return 0;
+       }
+
+       usbip_dbg_stub_rx("seqnum %d is not pending\n",
+                         pdu->u.cmd_unlink.seqnum);
+
+       /*
+        * The urb of the unlink target is not found in priv_init queue. It was
+        * already completed and its results is/was going to be sent by a
+        * CMD_RET pdu. In this case, usb_unlink_urb() is not needed. We only
+        * return the completeness of this unlink request to vhci_hcd.
+        */
+       stub_enqueue_ret_unlink(sdev, pdu->base.seqnum, 0);
+
+       spin_unlock_irqrestore(&sdev->priv_lock, flags);
+
+       return 0;
+}
+
+static int valid_request(struct stub_device *sdev, struct usbip_header *pdu)
+{
+       struct usbip_device *ud = &sdev->ud;
+       int valid = 0;
+
+       if (pdu->base.devid == sdev->devid) {
+               spin_lock_irq(&ud->lock);
+               if (ud->status == SDEV_ST_USED) {
+                       /* A request is valid. */
+                       valid = 1;
+               }
+               spin_unlock_irq(&ud->lock);
+       }
+
+       return valid;
+}
+
+static struct stub_priv *stub_priv_alloc(struct stub_device *sdev,
+                                        struct usbip_header *pdu)
+{
+       struct stub_priv *priv;
+       struct usbip_device *ud = &sdev->ud;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sdev->priv_lock, flags);
+
+       priv = kmem_cache_zalloc(stub_priv_cache, GFP_ATOMIC);
+       if (!priv) {
+               dev_err(&sdev->interface->dev, "alloc stub_priv\n");
+               spin_unlock_irqrestore(&sdev->priv_lock, flags);
+               usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC);
+               return NULL;
+       }
+
+       priv->seqnum = pdu->base.seqnum;
+       priv->sdev = sdev;
+
+       /*
+        * After a stub_priv is linked to a list_head,
+        * our error handler can free allocated data.
+        */
+       list_add_tail(&priv->list, &sdev->priv_init);
+
+       spin_unlock_irqrestore(&sdev->priv_lock, flags);
+
+       return priv;
+}
+
+static int get_pipe(struct stub_device *sdev, int epnum, int dir)
+{
+       struct usb_device *udev = sdev->udev;
+       struct usb_host_endpoint *ep;
+       struct usb_endpoint_descriptor *epd = NULL;
+
+       if (dir == USBIP_DIR_IN)
+               ep = udev->ep_in[epnum & 0x7f];
+       else
+               ep = udev->ep_out[epnum & 0x7f];
+       if (!ep) {
+               dev_err(&sdev->interface->dev, "no such endpoint?, %d\n",
+                       epnum);
+               BUG();
+       }
+
+       epd = &ep->desc;
+       if (usb_endpoint_xfer_control(epd)) {
+               if (dir == USBIP_DIR_OUT)
+                       return usb_sndctrlpipe(udev, epnum);
+               else
+                       return usb_rcvctrlpipe(udev, epnum);
+       }
+
+       if (usb_endpoint_xfer_bulk(epd)) {
+               if (dir == USBIP_DIR_OUT)
+                       return usb_sndbulkpipe(udev, epnum);
+               else
+                       return usb_rcvbulkpipe(udev, epnum);
+       }
+
+       if (usb_endpoint_xfer_int(epd)) {
+               if (dir == USBIP_DIR_OUT)
+                       return usb_sndintpipe(udev, epnum);
+               else
+                       return usb_rcvintpipe(udev, epnum);
+       }
+
+       if (usb_endpoint_xfer_isoc(epd)) {
+               if (dir == USBIP_DIR_OUT)
+                       return usb_sndisocpipe(udev, epnum);
+               else
+                       return usb_rcvisocpipe(udev, epnum);
+       }
+
+       /* NOT REACHED */
+       dev_err(&sdev->interface->dev, "get pipe, epnum %d\n", epnum);
+       return 0;
+}
+
+static void masking_bogus_flags(struct urb *urb)
+{
+       int                             xfertype;
+       struct usb_device               *dev;
+       struct usb_host_endpoint        *ep;
+       int                             is_out;
+       unsigned int    allowed;
+
+       if (!urb || urb->hcpriv || !urb->complete)
+               return;
+       dev = urb->dev;
+       if ((!dev) || (dev->state < USB_STATE_UNAUTHENTICATED))
+               return;
+
+       ep = (usb_pipein(urb->pipe) ? dev->ep_in : dev->ep_out)
+               [usb_pipeendpoint(urb->pipe)];
+       if (!ep)
+               return;
+
+       xfertype = usb_endpoint_type(&ep->desc);
+       if (xfertype == USB_ENDPOINT_XFER_CONTROL) {
+               struct usb_ctrlrequest *setup =
+                       (struct usb_ctrlrequest *) urb->setup_packet;
+
+               if (!setup)
+                       return;
+               is_out = !(setup->bRequestType & USB_DIR_IN) ||
+                       !setup->wLength;
+       } else {
+               is_out = usb_endpoint_dir_out(&ep->desc);
+       }
+
+       /* enforce simple/standard policy */
+       allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT |
+                  URB_DIR_MASK | URB_FREE_BUFFER);
+       switch (xfertype) {
+       case USB_ENDPOINT_XFER_BULK:
+               if (is_out)
+                       allowed |= URB_ZERO_PACKET;
+               /* FALLTHROUGH */
+       case USB_ENDPOINT_XFER_CONTROL:
+               allowed |= URB_NO_FSBR; /* only affects UHCI */
+               /* FALLTHROUGH */
+       default:                        /* all non-iso endpoints */
+               if (!is_out)
+                       allowed |= URB_SHORT_NOT_OK;
+               break;
+       case USB_ENDPOINT_XFER_ISOC:
+               allowed |= URB_ISO_ASAP;
+               break;
+       }
+       urb->transfer_flags &= allowed;
+}
+
+static void stub_recv_cmd_submit(struct stub_device *sdev,
+                                struct usbip_header *pdu)
+{
+       int ret;
+       struct stub_priv *priv;
+       struct usbip_device *ud = &sdev->ud;
+       struct usb_device *udev = sdev->udev;
+       int pipe = get_pipe(sdev, pdu->base.ep, pdu->base.direction);
+
+       priv = stub_priv_alloc(sdev, pdu);
+       if (!priv)
+               return;
+
+       /* setup a urb */
+       if (usb_pipeisoc(pipe))
+               priv->urb = usb_alloc_urb(pdu->u.cmd_submit.number_of_packets,
+                                         GFP_KERNEL);
+       else
+               priv->urb = usb_alloc_urb(0, GFP_KERNEL);
+
+       if (!priv->urb) {
+               dev_err(&sdev->interface->dev, "malloc urb\n");
+               usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC);
+               return;
+       }
+
+       /* allocate urb transfer buffer, if needed */
+       if (pdu->u.cmd_submit.transfer_buffer_length > 0) {
+               priv->urb->transfer_buffer =
+                       kzalloc(pdu->u.cmd_submit.transfer_buffer_length,
+                               GFP_KERNEL);
+               if (!priv->urb->transfer_buffer) {
+                       usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC);
+                       return;
+               }
+       }
+
+       /* copy urb setup packet */
+       priv->urb->setup_packet = kmemdup(&pdu->u.cmd_submit.setup, 8,
+                                         GFP_KERNEL);
+       if (!priv->urb->setup_packet) {
+               dev_err(&sdev->interface->dev, "allocate setup_packet\n");
+               usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC);
+               return;
+       }
+
+       /* set other members from the base header of pdu */
+       priv->urb->context                = (void *) priv;
+       priv->urb->dev                    = udev;
+       priv->urb->pipe                   = pipe;
+       priv->urb->complete               = stub_complete;
+
+       usbip_pack_pdu(pdu, priv->urb, USBIP_CMD_SUBMIT, 0);
+
+
+       if (usbip_recv_xbuff(ud, priv->urb) < 0)
+               return;
+
+       if (usbip_recv_iso(ud, priv->urb) < 0)
+               return;
+
+       /* no need to submit an intercepted request, but harmless? */
+       tweak_special_requests(priv->urb);
+
+       masking_bogus_flags(priv->urb);
+       /* urb is now ready to submit */
+       ret = usb_submit_urb(priv->urb, GFP_KERNEL);
+
+       if (ret == 0)
+               usbip_dbg_stub_rx("submit urb ok, seqnum %u\n",
+                                 pdu->base.seqnum);
+       else {
+               dev_err(&sdev->interface->dev, "submit_urb error, %d\n", ret);
+               usbip_dump_header(pdu);
+               usbip_dump_urb(priv->urb);
+
+               /*
+                * Pessimistic.
+                * This connection will be discarded.
+                */
+               usbip_event_add(ud, SDEV_EVENT_ERROR_SUBMIT);
+       }
+
+       usbip_dbg_stub_rx("Leave\n");
+}
+
+/* recv a pdu */
+static void stub_rx_pdu(struct usbip_device *ud)
+{
+       int ret;
+       struct usbip_header pdu;
+       struct stub_device *sdev = container_of(ud, struct stub_device, ud);
+       struct device *dev = &sdev->udev->dev;
+
+       usbip_dbg_stub_rx("Enter\n");
+
+       memset(&pdu, 0, sizeof(pdu));
+
+       /* receive a pdu header */
+       ret = usbip_recv(ud->tcp_socket, &pdu, sizeof(pdu));
+       if (ret != sizeof(pdu)) {
+               dev_err(dev, "recv a header, %d\n", ret);
+               usbip_event_add(ud, SDEV_EVENT_ERROR_TCP);
+               return;
+       }
+
+       usbip_header_correct_endian(&pdu, 0);
+
+       if (usbip_dbg_flag_stub_rx)
+               usbip_dump_header(&pdu);
+
+       if (!valid_request(sdev, &pdu)) {
+               dev_err(dev, "recv invalid request\n");
+               usbip_event_add(ud, SDEV_EVENT_ERROR_TCP);
+               return;
+       }
+
+       switch (pdu.base.command) {
+       case USBIP_CMD_UNLINK:
+               stub_recv_cmd_unlink(sdev, &pdu);
+               break;
+
+       case USBIP_CMD_SUBMIT:
+               stub_recv_cmd_submit(sdev, &pdu);
+               break;
+
+       default:
+               /* NOTREACHED */
+               dev_err(dev, "unknown pdu\n");
+               usbip_event_add(ud, SDEV_EVENT_ERROR_TCP);
+               break;
+       }
+}
+
+int stub_rx_loop(void *data)
+{
+       struct usbip_device *ud = data;
+
+       while (!kthread_should_stop()) {
+               if (usbip_event_happened(ud))
+                       break;
+
+               stub_rx_pdu(ud);
+       }
+
+       return 0;
+}
diff --git a/drivers/usb/usbip/stub_tx.c b/drivers/usb/usbip/stub_tx.c
new file mode 100644 (file)
index 0000000..dbcabc9
--- /dev/null
@@ -0,0 +1,398 @@
+/*
+ * Copyright (C) 2003-2008 Takahiro Hirofuchi
+ *
+ * This 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 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/kthread.h>
+#include <linux/socket.h>
+
+#include "usbip_common.h"
+#include "stub.h"
+
+static void stub_free_priv_and_urb(struct stub_priv *priv)
+{
+       struct urb *urb = priv->urb;
+
+       kfree(urb->setup_packet);
+       kfree(urb->transfer_buffer);
+       list_del(&priv->list);
+       kmem_cache_free(stub_priv_cache, priv);
+       usb_free_urb(urb);
+}
+
+/* be in spin_lock_irqsave(&sdev->priv_lock, flags) */
+void stub_enqueue_ret_unlink(struct stub_device *sdev, __u32 seqnum,
+                            __u32 status)
+{
+       struct stub_unlink *unlink;
+
+       unlink = kzalloc(sizeof(struct stub_unlink), GFP_ATOMIC);
+       if (!unlink) {
+               usbip_event_add(&sdev->ud, VDEV_EVENT_ERROR_MALLOC);
+               return;
+       }
+
+       unlink->seqnum = seqnum;
+       unlink->status = status;
+
+       list_add_tail(&unlink->list, &sdev->unlink_tx);
+}
+
+/**
+ * stub_complete - completion handler of a usbip urb
+ * @urb: pointer to the urb completed
+ *
+ * When a urb has completed, the USB core driver calls this function mostly in
+ * the interrupt context. To return the result of a urb, the completed urb is
+ * linked to the pending list of returning.
+ *
+ */
+void stub_complete(struct urb *urb)
+{
+       struct stub_priv *priv = (struct stub_priv *) urb->context;
+       struct stub_device *sdev = priv->sdev;
+       unsigned long flags;
+
+       usbip_dbg_stub_tx("complete! status %d\n", urb->status);
+
+       switch (urb->status) {
+       case 0:
+               /* OK */
+               break;
+       case -ENOENT:
+               dev_info(&urb->dev->dev,
+                        "stopped by a call to usb_kill_urb() because of cleaning up a virtual connection\n");
+               return;
+       case -ECONNRESET:
+               dev_info(&urb->dev->dev,
+                        "unlinked by a call to usb_unlink_urb()\n");
+               break;
+       case -EPIPE:
+               dev_info(&urb->dev->dev, "endpoint %d is stalled\n",
+                        usb_pipeendpoint(urb->pipe));
+               break;
+       case -ESHUTDOWN:
+               dev_info(&urb->dev->dev, "device removed?\n");
+               break;
+       default:
+               dev_info(&urb->dev->dev,
+                        "urb completion with non-zero status %d\n",
+                        urb->status);
+               break;
+       }
+
+       /* link a urb to the queue of tx. */
+       spin_lock_irqsave(&sdev->priv_lock, flags);
+       if (priv->unlinking) {
+               stub_enqueue_ret_unlink(sdev, priv->seqnum, urb->status);
+               stub_free_priv_and_urb(priv);
+       } else {
+               list_move_tail(&priv->list, &sdev->priv_tx);
+       }
+       spin_unlock_irqrestore(&sdev->priv_lock, flags);
+
+       /* wake up tx_thread */
+       wake_up(&sdev->tx_waitq);
+}
+
+static inline void setup_base_pdu(struct usbip_header_basic *base,
+                                 __u32 command, __u32 seqnum)
+{
+       base->command   = command;
+       base->seqnum    = seqnum;
+       base->devid     = 0;
+       base->ep        = 0;
+       base->direction = 0;
+}
+
+static void setup_ret_submit_pdu(struct usbip_header *rpdu, struct urb *urb)
+{
+       struct stub_priv *priv = (struct stub_priv *) urb->context;
+
+       setup_base_pdu(&rpdu->base, USBIP_RET_SUBMIT, priv->seqnum);
+       usbip_pack_pdu(rpdu, urb, USBIP_RET_SUBMIT, 1);
+}
+
+static void setup_ret_unlink_pdu(struct usbip_header *rpdu,
+                                struct stub_unlink *unlink)
+{
+       setup_base_pdu(&rpdu->base, USBIP_RET_UNLINK, unlink->seqnum);
+       rpdu->u.ret_unlink.status = unlink->status;
+}
+
+static struct stub_priv *dequeue_from_priv_tx(struct stub_device *sdev)
+{
+       unsigned long flags;
+       struct stub_priv *priv, *tmp;
+
+       spin_lock_irqsave(&sdev->priv_lock, flags);
+
+       list_for_each_entry_safe(priv, tmp, &sdev->priv_tx, list) {
+               list_move_tail(&priv->list, &sdev->priv_free);
+               spin_unlock_irqrestore(&sdev->priv_lock, flags);
+               return priv;
+       }
+
+       spin_unlock_irqrestore(&sdev->priv_lock, flags);
+
+       return NULL;
+}
+
+static int stub_send_ret_submit(struct stub_device *sdev)
+{
+       unsigned long flags;
+       struct stub_priv *priv, *tmp;
+
+       struct msghdr msg;
+       size_t txsize;
+
+       size_t total_size = 0;
+
+       while ((priv = dequeue_from_priv_tx(sdev)) != NULL) {
+               int ret;
+               struct urb *urb = priv->urb;
+               struct usbip_header pdu_header;
+               struct usbip_iso_packet_descriptor *iso_buffer = NULL;
+               struct kvec *iov = NULL;
+               int iovnum = 0;
+
+               txsize = 0;
+               memset(&pdu_header, 0, sizeof(pdu_header));
+               memset(&msg, 0, sizeof(msg));
+
+               if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
+                       iovnum = 2 + urb->number_of_packets;
+               else
+                       iovnum = 2;
+
+               iov = kcalloc(iovnum, sizeof(struct kvec), GFP_KERNEL);
+
+               if (!iov) {
+                       usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_MALLOC);
+                       return -1;
+               }
+
+               iovnum = 0;
+
+               /* 1. setup usbip_header */
+               setup_ret_submit_pdu(&pdu_header, urb);
+               usbip_dbg_stub_tx("setup txdata seqnum: %d urb: %p\n",
+                                 pdu_header.base.seqnum, urb);
+               usbip_header_correct_endian(&pdu_header, 1);
+
+               iov[iovnum].iov_base = &pdu_header;
+               iov[iovnum].iov_len  = sizeof(pdu_header);
+               iovnum++;
+               txsize += sizeof(pdu_header);
+
+               /* 2. setup transfer buffer */
+               if (usb_pipein(urb->pipe) &&
+                   usb_pipetype(urb->pipe) != PIPE_ISOCHRONOUS &&
+                   urb->actual_length > 0) {
+                       iov[iovnum].iov_base = urb->transfer_buffer;
+                       iov[iovnum].iov_len  = urb->actual_length;
+                       iovnum++;
+                       txsize += urb->actual_length;
+               } else if (usb_pipein(urb->pipe) &&
+                          usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+                       /*
+                        * For isochronous packets: actual length is the sum of
+                        * the actual length of the individual, packets, but as
+                        * the packet offsets are not changed there will be
+                        * padding between the packets. To optimally use the
+                        * bandwidth the padding is not transmitted.
+                        */
+
+                       int i;
+
+                       for (i = 0; i < urb->number_of_packets; i++) {
+                               iov[iovnum].iov_base = urb->transfer_buffer +
+                                       urb->iso_frame_desc[i].offset;
+                               iov[iovnum].iov_len =
+                                       urb->iso_frame_desc[i].actual_length;
+                               iovnum++;
+                               txsize += urb->iso_frame_desc[i].actual_length;
+                       }
+
+                       if (txsize != sizeof(pdu_header) + urb->actual_length) {
+                               dev_err(&sdev->interface->dev,
+                                       "actual length of urb %d does not match iso packet sizes %zu\n",
+                                       urb->actual_length,
+                                       txsize-sizeof(pdu_header));
+                               kfree(iov);
+                               usbip_event_add(&sdev->ud,
+                                               SDEV_EVENT_ERROR_TCP);
+                          return -1;
+                       }
+               }
+
+               /* 3. setup iso_packet_descriptor */
+               if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+                       ssize_t len = 0;
+
+                       iso_buffer = usbip_alloc_iso_desc_pdu(urb, &len);
+                       if (!iso_buffer) {
+                               usbip_event_add(&sdev->ud,
+                                               SDEV_EVENT_ERROR_MALLOC);
+                               kfree(iov);
+                               return -1;
+                       }
+
+                       iov[iovnum].iov_base = iso_buffer;
+                       iov[iovnum].iov_len  = len;
+                       txsize += len;
+                       iovnum++;
+               }
+
+               ret = kernel_sendmsg(sdev->ud.tcp_socket, &msg,
+                                               iov,  iovnum, txsize);
+               if (ret != txsize) {
+                       dev_err(&sdev->interface->dev,
+                               "sendmsg failed!, retval %d for %zd\n",
+                               ret, txsize);
+                       kfree(iov);
+                       kfree(iso_buffer);
+                       usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_TCP);
+                       return -1;
+               }
+
+               kfree(iov);
+               kfree(iso_buffer);
+
+               total_size += txsize;
+       }
+
+       spin_lock_irqsave(&sdev->priv_lock, flags);
+       list_for_each_entry_safe(priv, tmp, &sdev->priv_free, list) {
+               stub_free_priv_and_urb(priv);
+       }
+       spin_unlock_irqrestore(&sdev->priv_lock, flags);
+
+       return total_size;
+}
+
+static struct stub_unlink *dequeue_from_unlink_tx(struct stub_device *sdev)
+{
+       unsigned long flags;
+       struct stub_unlink *unlink, *tmp;
+
+       spin_lock_irqsave(&sdev->priv_lock, flags);
+
+       list_for_each_entry_safe(unlink, tmp, &sdev->unlink_tx, list) {
+               list_move_tail(&unlink->list, &sdev->unlink_free);
+               spin_unlock_irqrestore(&sdev->priv_lock, flags);
+               return unlink;
+       }
+
+       spin_unlock_irqrestore(&sdev->priv_lock, flags);
+
+       return NULL;
+}
+
+static int stub_send_ret_unlink(struct stub_device *sdev)
+{
+       unsigned long flags;
+       struct stub_unlink *unlink, *tmp;
+
+       struct msghdr msg;
+       struct kvec iov[1];
+       size_t txsize;
+
+       size_t total_size = 0;
+
+       while ((unlink = dequeue_from_unlink_tx(sdev)) != NULL) {
+               int ret;
+               struct usbip_header pdu_header;
+
+               txsize = 0;
+               memset(&pdu_header, 0, sizeof(pdu_header));
+               memset(&msg, 0, sizeof(msg));
+               memset(&iov, 0, sizeof(iov));
+
+               usbip_dbg_stub_tx("setup ret unlink %lu\n", unlink->seqnum);
+
+               /* 1. setup usbip_header */
+               setup_ret_unlink_pdu(&pdu_header, unlink);
+               usbip_header_correct_endian(&pdu_header, 1);
+
+               iov[0].iov_base = &pdu_header;
+               iov[0].iov_len  = sizeof(pdu_header);
+               txsize += sizeof(pdu_header);
+
+               ret = kernel_sendmsg(sdev->ud.tcp_socket, &msg, iov,
+                                    1, txsize);
+               if (ret != txsize) {
+                       dev_err(&sdev->interface->dev,
+                               "sendmsg failed!, retval %d for %zd\n",
+                               ret, txsize);
+                       usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_TCP);
+                       return -1;
+               }
+
+               usbip_dbg_stub_tx("send txdata\n");
+               total_size += txsize;
+       }
+
+       spin_lock_irqsave(&sdev->priv_lock, flags);
+
+       list_for_each_entry_safe(unlink, tmp, &sdev->unlink_free, list) {
+               list_del(&unlink->list);
+               kfree(unlink);
+       }
+
+       spin_unlock_irqrestore(&sdev->priv_lock, flags);
+
+       return total_size;
+}
+
+int stub_tx_loop(void *data)
+{
+       struct usbip_device *ud = data;
+       struct stub_device *sdev = container_of(ud, struct stub_device, ud);
+
+       while (!kthread_should_stop()) {
+               if (usbip_event_happened(ud))
+                       break;
+
+               /*
+                * send_ret_submit comes earlier than send_ret_unlink.  stub_rx
+                * looks at only priv_init queue. If the completion of a URB is
+                * earlier than the receive of CMD_UNLINK, priv is moved to
+                * priv_tx queue and stub_rx does not find the target priv. In
+                * this case, vhci_rx receives the result of the submit request
+                * and then receives the result of the unlink request. The
+                * result of the submit is given back to the usbcore as the
+                * completion of the unlink request. The request of the
+                * unlink is ignored. This is ok because a driver who calls
+                * usb_unlink_urb() understands the unlink was too late by
+                * getting the status of the given-backed URB which has the
+                * status of usb_submit_urb().
+                */
+               if (stub_send_ret_submit(sdev) < 0)
+                       break;
+
+               if (stub_send_ret_unlink(sdev) < 0)
+                       break;
+
+               wait_event_interruptible(sdev->tx_waitq,
+                                        (!list_empty(&sdev->priv_tx) ||
+                                         !list_empty(&sdev->unlink_tx) ||
+                                         kthread_should_stop()));
+       }
+
+       return 0;
+}
diff --git a/drivers/usb/usbip/usbip_common.c b/drivers/usb/usbip/usbip_common.c
new file mode 100644 (file)
index 0000000..facaaf0
--- /dev/null
@@ -0,0 +1,776 @@
+/*
+ * Copyright (C) 2003-2008 Takahiro Hirofuchi
+ *
+ * This 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 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 <asm/byteorder.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/stat.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <net/sock.h>
+
+#include "usbip_common.h"
+
+#define DRIVER_AUTHOR "Takahiro Hirofuchi <hirofuchi@users.sourceforge.net>"
+#define DRIVER_DESC "USB/IP Core"
+
+#ifdef CONFIG_USBIP_DEBUG
+unsigned long usbip_debug_flag = 0xffffffff;
+#else
+unsigned long usbip_debug_flag;
+#endif
+EXPORT_SYMBOL_GPL(usbip_debug_flag);
+module_param(usbip_debug_flag, ulong, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(usbip_debug_flag, "debug flags (defined in usbip_common.h)");
+
+/* FIXME */
+struct device_attribute dev_attr_usbip_debug;
+EXPORT_SYMBOL_GPL(dev_attr_usbip_debug);
+
+static ssize_t usbip_debug_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%lx\n", usbip_debug_flag);
+}
+
+static ssize_t usbip_debug_store(struct device *dev,
+                                struct device_attribute *attr, const char *buf,
+                                size_t count)
+{
+       if (sscanf(buf, "%lx", &usbip_debug_flag) != 1)
+               return -EINVAL;
+       return count;
+}
+DEVICE_ATTR_RW(usbip_debug);
+
+static void usbip_dump_buffer(char *buff, int bufflen)
+{
+       print_hex_dump(KERN_DEBUG, "usbip-core", DUMP_PREFIX_OFFSET, 16, 4,
+                      buff, bufflen, false);
+}
+
+static void usbip_dump_pipe(unsigned int p)
+{
+       unsigned char type = usb_pipetype(p);
+       unsigned char ep   = usb_pipeendpoint(p);
+       unsigned char dev  = usb_pipedevice(p);
+       unsigned char dir  = usb_pipein(p);
+
+       pr_debug("dev(%d) ep(%d) [%s] ", dev, ep, dir ? "IN" : "OUT");
+
+       switch (type) {
+       case PIPE_ISOCHRONOUS:
+               pr_debug("ISO\n");
+               break;
+       case PIPE_INTERRUPT:
+               pr_debug("INT\n");
+               break;
+       case PIPE_CONTROL:
+               pr_debug("CTRL\n");
+               break;
+       case PIPE_BULK:
+               pr_debug("BULK\n");
+               break;
+       default:
+               pr_debug("ERR\n");
+               break;
+       }
+}
+
+static void usbip_dump_usb_device(struct usb_device *udev)
+{
+       struct device *dev = &udev->dev;
+       int i;
+
+       dev_dbg(dev, "       devnum(%d) devpath(%s) usb speed(%s)",
+               udev->devnum, udev->devpath, usb_speed_string(udev->speed));
+
+       pr_debug("tt %p, ttport %d\n", udev->tt, udev->ttport);
+
+       dev_dbg(dev, "                    ");
+       for (i = 0; i < 16; i++)
+               pr_debug(" %2u", i);
+       pr_debug("\n");
+
+       dev_dbg(dev, "       toggle0(IN) :");
+       for (i = 0; i < 16; i++)
+               pr_debug(" %2u", (udev->toggle[0] & (1 << i)) ? 1 : 0);
+       pr_debug("\n");
+
+       dev_dbg(dev, "       toggle1(OUT):");
+       for (i = 0; i < 16; i++)
+               pr_debug(" %2u", (udev->toggle[1] & (1 << i)) ? 1 : 0);
+       pr_debug("\n");
+
+       dev_dbg(dev, "       epmaxp_in   :");
+       for (i = 0; i < 16; i++) {
+               if (udev->ep_in[i])
+                       pr_debug(" %2u",
+                           le16_to_cpu(udev->ep_in[i]->desc.wMaxPacketSize));
+       }
+       pr_debug("\n");
+
+       dev_dbg(dev, "       epmaxp_out  :");
+       for (i = 0; i < 16; i++) {
+               if (udev->ep_out[i])
+                       pr_debug(" %2u",
+                           le16_to_cpu(udev->ep_out[i]->desc.wMaxPacketSize));
+       }
+       pr_debug("\n");
+
+       dev_dbg(dev, "parent %p, bus %p\n", udev->parent, udev->bus);
+
+       dev_dbg(dev,
+               "descriptor %p, config %p, actconfig %p, rawdescriptors %p\n",
+               &udev->descriptor, udev->config,
+               udev->actconfig, udev->rawdescriptors);
+
+       dev_dbg(dev, "have_langid %d, string_langid %d\n",
+               udev->have_langid, udev->string_langid);
+
+       dev_dbg(dev, "maxchild %d\n", udev->maxchild);
+}
+
+static void usbip_dump_request_type(__u8 rt)
+{
+       switch (rt & USB_RECIP_MASK) {
+       case USB_RECIP_DEVICE:
+               pr_debug("DEVICE");
+               break;
+       case USB_RECIP_INTERFACE:
+               pr_debug("INTERF");
+               break;
+       case USB_RECIP_ENDPOINT:
+               pr_debug("ENDPOI");
+               break;
+       case USB_RECIP_OTHER:
+               pr_debug("OTHER ");
+               break;
+       default:
+               pr_debug("------");
+               break;
+       }
+}
+
+static void usbip_dump_usb_ctrlrequest(struct usb_ctrlrequest *cmd)
+{
+       if (!cmd) {
+               pr_debug("       : null pointer\n");
+               return;
+       }
+
+       pr_debug("       ");
+       pr_debug("bRequestType(%02X) bRequest(%02X) wValue(%04X) wIndex(%04X) wLength(%04X) ",
+                cmd->bRequestType, cmd->bRequest,
+                cmd->wValue, cmd->wIndex, cmd->wLength);
+       pr_debug("\n       ");
+
+       if ((cmd->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
+               pr_debug("STANDARD ");
+               switch (cmd->bRequest) {
+               case USB_REQ_GET_STATUS:
+                       pr_debug("GET_STATUS\n");
+                       break;
+               case USB_REQ_CLEAR_FEATURE:
+                       pr_debug("CLEAR_FEAT\n");
+                       break;
+               case USB_REQ_SET_FEATURE:
+                       pr_debug("SET_FEAT\n");
+                       break;
+               case USB_REQ_SET_ADDRESS:
+                       pr_debug("SET_ADDRRS\n");
+                       break;
+               case USB_REQ_GET_DESCRIPTOR:
+                       pr_debug("GET_DESCRI\n");
+                       break;
+               case USB_REQ_SET_DESCRIPTOR:
+                       pr_debug("SET_DESCRI\n");
+                       break;
+               case USB_REQ_GET_CONFIGURATION:
+                       pr_debug("GET_CONFIG\n");
+                       break;
+               case USB_REQ_SET_CONFIGURATION:
+                       pr_debug("SET_CONFIG\n");
+                       break;
+               case USB_REQ_GET_INTERFACE:
+                       pr_debug("GET_INTERF\n");
+                       break;
+               case USB_REQ_SET_INTERFACE:
+                       pr_debug("SET_INTERF\n");
+                       break;
+               case USB_REQ_SYNCH_FRAME:
+                       pr_debug("SYNC_FRAME\n");
+                       break;
+               default:
+                       pr_debug("REQ(%02X)\n", cmd->bRequest);
+                       break;
+               }
+               usbip_dump_request_type(cmd->bRequestType);
+       } else if ((cmd->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS) {
+               pr_debug("CLASS\n");
+       } else if ((cmd->bRequestType & USB_TYPE_MASK) == USB_TYPE_VENDOR) {
+               pr_debug("VENDOR\n");
+       } else if ((cmd->bRequestType & USB_TYPE_MASK) == USB_TYPE_RESERVED) {
+               pr_debug("RESERVED\n");
+       }
+}
+
+void usbip_dump_urb(struct urb *urb)
+{
+       struct device *dev;
+
+       if (!urb) {
+               pr_debug("urb: null pointer!!\n");
+               return;
+       }
+
+       if (!urb->dev) {
+               pr_debug("urb->dev: null pointer!!\n");
+               return;
+       }
+
+       dev = &urb->dev->dev;
+
+       dev_dbg(dev, "   urb                   :%p\n", urb);
+       dev_dbg(dev, "   dev                   :%p\n", urb->dev);
+
+       usbip_dump_usb_device(urb->dev);
+
+       dev_dbg(dev, "   pipe                  :%08x ", urb->pipe);
+
+       usbip_dump_pipe(urb->pipe);
+
+       dev_dbg(dev, "   status                :%d\n", urb->status);
+       dev_dbg(dev, "   transfer_flags        :%08X\n", urb->transfer_flags);
+       dev_dbg(dev, "   transfer_buffer       :%p\n", urb->transfer_buffer);
+       dev_dbg(dev, "   transfer_buffer_length:%d\n",
+                                               urb->transfer_buffer_length);
+       dev_dbg(dev, "   actual_length         :%d\n", urb->actual_length);
+       dev_dbg(dev, "   setup_packet          :%p\n", urb->setup_packet);
+
+       if (urb->setup_packet && usb_pipetype(urb->pipe) == PIPE_CONTROL)
+               usbip_dump_usb_ctrlrequest(
+                       (struct usb_ctrlrequest *)urb->setup_packet);
+
+       dev_dbg(dev, "   start_frame           :%d\n", urb->start_frame);
+       dev_dbg(dev, "   number_of_packets     :%d\n", urb->number_of_packets);
+       dev_dbg(dev, "   interval              :%d\n", urb->interval);
+       dev_dbg(dev, "   error_count           :%d\n", urb->error_count);
+       dev_dbg(dev, "   context               :%p\n", urb->context);
+       dev_dbg(dev, "   complete              :%p\n", urb->complete);
+}
+EXPORT_SYMBOL_GPL(usbip_dump_urb);
+
+void usbip_dump_header(struct usbip_header *pdu)
+{
+       pr_debug("BASE: cmd %u seq %u devid %u dir %u ep %u\n",
+                pdu->base.command,
+                pdu->base.seqnum,
+                pdu->base.devid,
+                pdu->base.direction,
+                pdu->base.ep);
+
+       switch (pdu->base.command) {
+       case USBIP_CMD_SUBMIT:
+               pr_debug("USBIP_CMD_SUBMIT: x_flags %u x_len %u sf %u #p %d iv %d\n",
+                        pdu->u.cmd_submit.transfer_flags,
+                        pdu->u.cmd_submit.transfer_buffer_length,
+                        pdu->u.cmd_submit.start_frame,
+                        pdu->u.cmd_submit.number_of_packets,
+                        pdu->u.cmd_submit.interval);
+               break;
+       case USBIP_CMD_UNLINK:
+               pr_debug("USBIP_CMD_UNLINK: seq %u\n",
+                        pdu->u.cmd_unlink.seqnum);
+               break;
+       case USBIP_RET_SUBMIT:
+               pr_debug("USBIP_RET_SUBMIT: st %d al %u sf %d #p %d ec %d\n",
+                        pdu->u.ret_submit.status,
+                        pdu->u.ret_submit.actual_length,
+                        pdu->u.ret_submit.start_frame,
+                        pdu->u.ret_submit.number_of_packets,
+                        pdu->u.ret_submit.error_count);
+               break;
+       case USBIP_RET_UNLINK:
+               pr_debug("USBIP_RET_UNLINK: status %d\n",
+                        pdu->u.ret_unlink.status);
+               break;
+       default:
+               /* NOT REACHED */
+               pr_err("unknown command\n");
+               break;
+       }
+}
+EXPORT_SYMBOL_GPL(usbip_dump_header);
+
+/* Receive data over TCP/IP. */
+int usbip_recv(struct socket *sock, void *buf, int size)
+{
+       int result;
+       struct msghdr msg;
+       struct kvec iov;
+       int total = 0;
+
+       /* for blocks of if (usbip_dbg_flag_xmit) */
+       char *bp = buf;
+       int osize = size;
+
+       usbip_dbg_xmit("enter\n");
+
+       if (!sock || !buf || !size) {
+               pr_err("invalid arg, sock %p buff %p size %d\n", sock, buf,
+                      size);
+               return -EINVAL;
+       }
+
+       do {
+               sock->sk->sk_allocation = GFP_NOIO;
+               iov.iov_base    = buf;
+               iov.iov_len     = size;
+               msg.msg_name    = NULL;
+               msg.msg_namelen = 0;
+               msg.msg_control = NULL;
+               msg.msg_controllen = 0;
+               msg.msg_flags      = MSG_NOSIGNAL;
+
+               result = kernel_recvmsg(sock, &msg, &iov, 1, size, MSG_WAITALL);
+               if (result <= 0) {
+                       pr_debug("receive sock %p buf %p size %u ret %d total %d\n",
+                                sock, buf, size, result, total);
+                       goto err;
+               }
+
+               size -= result;
+               buf += result;
+               total += result;
+       } while (size > 0);
+
+       if (usbip_dbg_flag_xmit) {
+               if (!in_interrupt())
+                       pr_debug("%-10s:", current->comm);
+               else
+                       pr_debug("interrupt  :");
+
+               pr_debug("receiving....\n");
+               usbip_dump_buffer(bp, osize);
+               pr_debug("received, osize %d ret %d size %d total %d\n",
+                        osize, result, size, total);
+       }
+
+       return total;
+
+err:
+       return result;
+}
+EXPORT_SYMBOL_GPL(usbip_recv);
+
+/* there may be more cases to tweak the flags. */
+static unsigned int tweak_transfer_flags(unsigned int flags)
+{
+       flags &= ~URB_NO_TRANSFER_DMA_MAP;
+       return flags;
+}
+
+static void usbip_pack_cmd_submit(struct usbip_header *pdu, struct urb *urb,
+                                 int pack)
+{
+       struct usbip_header_cmd_submit *spdu = &pdu->u.cmd_submit;
+
+       /*
+        * Some members are not still implemented in usbip. I hope this issue
+        * will be discussed when usbip is ported to other operating systems.
+        */
+       if (pack) {
+               spdu->transfer_flags =
+                       tweak_transfer_flags(urb->transfer_flags);
+               spdu->transfer_buffer_length    = urb->transfer_buffer_length;
+               spdu->start_frame               = urb->start_frame;
+               spdu->number_of_packets         = urb->number_of_packets;
+               spdu->interval                  = urb->interval;
+       } else  {
+               urb->transfer_flags         = spdu->transfer_flags;
+               urb->transfer_buffer_length = spdu->transfer_buffer_length;
+               urb->start_frame            = spdu->start_frame;
+               urb->number_of_packets      = spdu->number_of_packets;
+               urb->interval               = spdu->interval;
+       }
+}
+
+static void usbip_pack_ret_submit(struct usbip_header *pdu, struct urb *urb,
+                                 int pack)
+{
+       struct usbip_header_ret_submit *rpdu = &pdu->u.ret_submit;
+
+       if (pack) {
+               rpdu->status            = urb->status;
+               rpdu->actual_length     = urb->actual_length;
+               rpdu->start_frame       = urb->start_frame;
+               rpdu->number_of_packets = urb->number_of_packets;
+               rpdu->error_count       = urb->error_count;
+       } else {
+               urb->status             = rpdu->status;
+               urb->actual_length      = rpdu->actual_length;
+               urb->start_frame        = rpdu->start_frame;
+               urb->number_of_packets = rpdu->number_of_packets;
+               urb->error_count        = rpdu->error_count;
+       }
+}
+
+void usbip_pack_pdu(struct usbip_header *pdu, struct urb *urb, int cmd,
+                   int pack)
+{
+       switch (cmd) {
+       case USBIP_CMD_SUBMIT:
+               usbip_pack_cmd_submit(pdu, urb, pack);
+               break;
+       case USBIP_RET_SUBMIT:
+               usbip_pack_ret_submit(pdu, urb, pack);
+               break;
+       default:
+               /* NOT REACHED */
+               pr_err("unknown command\n");
+               break;
+       }
+}
+EXPORT_SYMBOL_GPL(usbip_pack_pdu);
+
+static void correct_endian_basic(struct usbip_header_basic *base, int send)
+{
+       if (send) {
+               base->command   = cpu_to_be32(base->command);
+               base->seqnum    = cpu_to_be32(base->seqnum);
+               base->devid     = cpu_to_be32(base->devid);
+               base->direction = cpu_to_be32(base->direction);
+               base->ep        = cpu_to_be32(base->ep);
+       } else {
+               base->command   = be32_to_cpu(base->command);
+               base->seqnum    = be32_to_cpu(base->seqnum);
+               base->devid     = be32_to_cpu(base->devid);
+               base->direction = be32_to_cpu(base->direction);
+               base->ep        = be32_to_cpu(base->ep);
+       }
+}
+
+static void correct_endian_cmd_submit(struct usbip_header_cmd_submit *pdu,
+                                     int send)
+{
+       if (send) {
+               pdu->transfer_flags = cpu_to_be32(pdu->transfer_flags);
+
+               cpu_to_be32s(&pdu->transfer_buffer_length);
+               cpu_to_be32s(&pdu->start_frame);
+               cpu_to_be32s(&pdu->number_of_packets);
+               cpu_to_be32s(&pdu->interval);
+       } else {
+               pdu->transfer_flags = be32_to_cpu(pdu->transfer_flags);
+
+               be32_to_cpus(&pdu->transfer_buffer_length);
+               be32_to_cpus(&pdu->start_frame);
+               be32_to_cpus(&pdu->number_of_packets);
+               be32_to_cpus(&pdu->interval);
+       }
+}
+
+static void correct_endian_ret_submit(struct usbip_header_ret_submit *pdu,
+                                     int send)
+{
+       if (send) {
+               cpu_to_be32s(&pdu->status);
+               cpu_to_be32s(&pdu->actual_length);
+               cpu_to_be32s(&pdu->start_frame);
+               cpu_to_be32s(&pdu->number_of_packets);
+               cpu_to_be32s(&pdu->error_count);
+       } else {
+               be32_to_cpus(&pdu->status);
+               be32_to_cpus(&pdu->actual_length);
+               be32_to_cpus(&pdu->start_frame);
+               be32_to_cpus(&pdu->number_of_packets);
+               be32_to_cpus(&pdu->error_count);
+       }
+}
+
+static void correct_endian_cmd_unlink(struct usbip_header_cmd_unlink *pdu,
+                                     int send)
+{
+       if (send)
+               pdu->seqnum = cpu_to_be32(pdu->seqnum);
+       else
+               pdu->seqnum = be32_to_cpu(pdu->seqnum);
+}
+
+static void correct_endian_ret_unlink(struct usbip_header_ret_unlink *pdu,
+                                     int send)
+{
+       if (send)
+               cpu_to_be32s(&pdu->status);
+       else
+               be32_to_cpus(&pdu->status);
+}
+
+void usbip_header_correct_endian(struct usbip_header *pdu, int send)
+{
+       __u32 cmd = 0;
+
+       if (send)
+               cmd = pdu->base.command;
+
+       correct_endian_basic(&pdu->base, send);
+
+       if (!send)
+               cmd = pdu->base.command;
+
+       switch (cmd) {
+       case USBIP_CMD_SUBMIT:
+               correct_endian_cmd_submit(&pdu->u.cmd_submit, send);
+               break;
+       case USBIP_RET_SUBMIT:
+               correct_endian_ret_submit(&pdu->u.ret_submit, send);
+               break;
+       case USBIP_CMD_UNLINK:
+               correct_endian_cmd_unlink(&pdu->u.cmd_unlink, send);
+               break;
+       case USBIP_RET_UNLINK:
+               correct_endian_ret_unlink(&pdu->u.ret_unlink, send);
+               break;
+       default:
+               /* NOT REACHED */
+               pr_err("unknown command\n");
+               break;
+       }
+}
+EXPORT_SYMBOL_GPL(usbip_header_correct_endian);
+
+static void usbip_iso_packet_correct_endian(
+               struct usbip_iso_packet_descriptor *iso, int send)
+{
+       /* does not need all members. but copy all simply. */
+       if (send) {
+               iso->offset     = cpu_to_be32(iso->offset);
+               iso->length     = cpu_to_be32(iso->length);
+               iso->status     = cpu_to_be32(iso->status);
+               iso->actual_length = cpu_to_be32(iso->actual_length);
+       } else {
+               iso->offset     = be32_to_cpu(iso->offset);
+               iso->length     = be32_to_cpu(iso->length);
+               iso->status     = be32_to_cpu(iso->status);
+               iso->actual_length = be32_to_cpu(iso->actual_length);
+       }
+}
+
+static void usbip_pack_iso(struct usbip_iso_packet_descriptor *iso,
+                          struct usb_iso_packet_descriptor *uiso, int pack)
+{
+       if (pack) {
+               iso->offset             = uiso->offset;
+               iso->length             = uiso->length;
+               iso->status             = uiso->status;
+               iso->actual_length      = uiso->actual_length;
+       } else {
+               uiso->offset            = iso->offset;
+               uiso->length            = iso->length;
+               uiso->status            = iso->status;
+               uiso->actual_length     = iso->actual_length;
+       }
+}
+
+/* must free buffer */
+struct usbip_iso_packet_descriptor*
+usbip_alloc_iso_desc_pdu(struct urb *urb, ssize_t *bufflen)
+{
+       struct usbip_iso_packet_descriptor *iso;
+       int np = urb->number_of_packets;
+       ssize_t size = np * sizeof(*iso);
+       int i;
+
+       iso = kzalloc(size, GFP_KERNEL);
+       if (!iso)
+               return NULL;
+
+       for (i = 0; i < np; i++) {
+               usbip_pack_iso(&iso[i], &urb->iso_frame_desc[i], 1);
+               usbip_iso_packet_correct_endian(&iso[i], 1);
+       }
+
+       *bufflen = size;
+
+       return iso;
+}
+EXPORT_SYMBOL_GPL(usbip_alloc_iso_desc_pdu);
+
+/* some members of urb must be substituted before. */
+int usbip_recv_iso(struct usbip_device *ud, struct urb *urb)
+{
+       void *buff;
+       struct usbip_iso_packet_descriptor *iso;
+       int np = urb->number_of_packets;
+       int size = np * sizeof(*iso);
+       int i;
+       int ret;
+       int total_length = 0;
+
+       if (!usb_pipeisoc(urb->pipe))
+               return 0;
+
+       /* my Bluetooth dongle gets ISO URBs which are np = 0 */
+       if (np == 0)
+               return 0;
+
+       buff = kzalloc(size, GFP_KERNEL);
+       if (!buff)
+               return -ENOMEM;
+
+       ret = usbip_recv(ud->tcp_socket, buff, size);
+       if (ret != size) {
+               dev_err(&urb->dev->dev, "recv iso_frame_descriptor, %d\n",
+                       ret);
+               kfree(buff);
+
+               if (ud->side == USBIP_STUB)
+                       usbip_event_add(ud, SDEV_EVENT_ERROR_TCP);
+               else
+                       usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
+
+               return -EPIPE;
+       }
+
+       iso = (struct usbip_iso_packet_descriptor *) buff;
+       for (i = 0; i < np; i++) {
+               usbip_iso_packet_correct_endian(&iso[i], 0);
+               usbip_pack_iso(&iso[i], &urb->iso_frame_desc[i], 0);
+               total_length += urb->iso_frame_desc[i].actual_length;
+       }
+
+       kfree(buff);
+
+       if (total_length != urb->actual_length) {
+               dev_err(&urb->dev->dev,
+                       "total length of iso packets %d not equal to actual length of buffer %d\n",
+                       total_length, urb->actual_length);
+
+               if (ud->side == USBIP_STUB)
+                       usbip_event_add(ud, SDEV_EVENT_ERROR_TCP);
+               else
+                       usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
+
+               return -EPIPE;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(usbip_recv_iso);
+
+/*
+ * This functions restores the padding which was removed for optimizing
+ * the bandwidth during transfer over tcp/ip
+ *
+ * buffer and iso packets need to be stored and be in propeper endian in urb
+ * before calling this function
+ */
+void usbip_pad_iso(struct usbip_device *ud, struct urb *urb)
+{
+       int np = urb->number_of_packets;
+       int i;
+       int actualoffset = urb->actual_length;
+
+       if (!usb_pipeisoc(urb->pipe))
+               return;
+
+       /* if no packets or length of data is 0, then nothing to unpack */
+       if (np == 0 || urb->actual_length == 0)
+               return;
+
+       /*
+        * if actual_length is transfer_buffer_length then no padding is
+        * present.
+        */
+       if (urb->actual_length == urb->transfer_buffer_length)
+               return;
+
+       /*
+        * loop over all packets from last to first (to prevent overwritting
+        * memory when padding) and move them into the proper place
+        */
+       for (i = np-1; i > 0; i--) {
+               actualoffset -= urb->iso_frame_desc[i].actual_length;
+               memmove(urb->transfer_buffer + urb->iso_frame_desc[i].offset,
+                       urb->transfer_buffer + actualoffset,
+                       urb->iso_frame_desc[i].actual_length);
+       }
+}
+EXPORT_SYMBOL_GPL(usbip_pad_iso);
+
+/* some members of urb must be substituted before. */
+int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb)
+{
+       int ret;
+       int size;
+
+       if (ud->side == USBIP_STUB) {
+               /* the direction of urb must be OUT. */
+               if (usb_pipein(urb->pipe))
+                       return 0;
+
+               size = urb->transfer_buffer_length;
+       } else {
+               /* the direction of urb must be IN. */
+               if (usb_pipeout(urb->pipe))
+                       return 0;
+
+               size = urb->actual_length;
+       }
+
+       /* no need to recv xbuff */
+       if (!(size > 0))
+               return 0;
+
+       ret = usbip_recv(ud->tcp_socket, urb->transfer_buffer, size);
+       if (ret != size) {
+               dev_err(&urb->dev->dev, "recv xbuf, %d\n", ret);
+               if (ud->side == USBIP_STUB) {
+                       usbip_event_add(ud, SDEV_EVENT_ERROR_TCP);
+               } else {
+                       usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
+                       return -EPIPE;
+               }
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(usbip_recv_xbuff);
+
+static int __init usbip_core_init(void)
+{
+       pr_info(DRIVER_DESC " v" USBIP_VERSION "\n");
+       return 0;
+}
+
+static void __exit usbip_core_exit(void)
+{
+       return;
+}
+
+module_init(usbip_core_init);
+module_exit(usbip_core_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_VERSION(USBIP_VERSION);
diff --git a/drivers/usb/usbip/usbip_common.h b/drivers/usb/usbip/usbip_common.h
new file mode 100644 (file)
index 0000000..86b0847
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 2003-2008 Takahiro Hirofuchi
+ *
+ * This 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 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 __USBIP_COMMON_H
+#define __USBIP_COMMON_H
+
+#include <linux/compiler.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/net.h>
+#include <linux/printk.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/usb.h>
+#include <linux/wait.h>
+#include <uapi/linux/usbip.h>
+
+#define USBIP_VERSION "1.0.0"
+
+#undef pr_fmt
+
+#ifdef DEBUG
+#define pr_fmt(fmt)     KBUILD_MODNAME ": %s:%d: " fmt, __func__, __LINE__
+#else
+#define pr_fmt(fmt)     KBUILD_MODNAME ": " fmt
+#endif
+
+enum {
+       usbip_debug_xmit        = (1 << 0),
+       usbip_debug_sysfs       = (1 << 1),
+       usbip_debug_urb         = (1 << 2),
+       usbip_debug_eh          = (1 << 3),
+
+       usbip_debug_stub_cmp    = (1 << 8),
+       usbip_debug_stub_dev    = (1 << 9),
+       usbip_debug_stub_rx     = (1 << 10),
+       usbip_debug_stub_tx     = (1 << 11),
+
+       usbip_debug_vhci_rh     = (1 << 8),
+       usbip_debug_vhci_hc     = (1 << 9),
+       usbip_debug_vhci_rx     = (1 << 10),
+       usbip_debug_vhci_tx     = (1 << 11),
+       usbip_debug_vhci_sysfs  = (1 << 12)
+};
+
+#define usbip_dbg_flag_xmit    (usbip_debug_flag & usbip_debug_xmit)
+#define usbip_dbg_flag_vhci_rh (usbip_debug_flag & usbip_debug_vhci_rh)
+#define usbip_dbg_flag_vhci_hc (usbip_debug_flag & usbip_debug_vhci_hc)
+#define usbip_dbg_flag_vhci_rx (usbip_debug_flag & usbip_debug_vhci_rx)
+#define usbip_dbg_flag_vhci_tx (usbip_debug_flag & usbip_debug_vhci_tx)
+#define usbip_dbg_flag_stub_rx (usbip_debug_flag & usbip_debug_stub_rx)
+#define usbip_dbg_flag_stub_tx (usbip_debug_flag & usbip_debug_stub_tx)
+#define usbip_dbg_flag_vhci_sysfs  (usbip_debug_flag & usbip_debug_vhci_sysfs)
+
+extern unsigned long usbip_debug_flag;
+extern struct device_attribute dev_attr_usbip_debug;
+
+#define usbip_dbg_with_flag(flag, fmt, args...)                \
+       do {                                            \
+               if (flag & usbip_debug_flag)            \
+                       pr_debug(fmt, ##args);          \
+       } while (0)
+
+#define usbip_dbg_sysfs(fmt, args...) \
+       usbip_dbg_with_flag(usbip_debug_sysfs, fmt , ##args)
+#define usbip_dbg_xmit(fmt, args...) \
+       usbip_dbg_with_flag(usbip_debug_xmit, fmt , ##args)
+#define usbip_dbg_urb(fmt, args...) \
+       usbip_dbg_with_flag(usbip_debug_urb, fmt , ##args)
+#define usbip_dbg_eh(fmt, args...) \
+       usbip_dbg_with_flag(usbip_debug_eh, fmt , ##args)
+
+#define usbip_dbg_vhci_rh(fmt, args...)        \
+       usbip_dbg_with_flag(usbip_debug_vhci_rh, fmt , ##args)
+#define usbip_dbg_vhci_hc(fmt, args...)        \
+       usbip_dbg_with_flag(usbip_debug_vhci_hc, fmt , ##args)
+#define usbip_dbg_vhci_rx(fmt, args...)        \
+       usbip_dbg_with_flag(usbip_debug_vhci_rx, fmt , ##args)
+#define usbip_dbg_vhci_tx(fmt, args...)        \
+       usbip_dbg_with_flag(usbip_debug_vhci_tx, fmt , ##args)
+#define usbip_dbg_vhci_sysfs(fmt, args...) \
+       usbip_dbg_with_flag(usbip_debug_vhci_sysfs, fmt , ##args)
+
+#define usbip_dbg_stub_cmp(fmt, args...) \
+       usbip_dbg_with_flag(usbip_debug_stub_cmp, fmt , ##args)
+#define usbip_dbg_stub_rx(fmt, args...) \
+       usbip_dbg_with_flag(usbip_debug_stub_rx, fmt , ##args)
+#define usbip_dbg_stub_tx(fmt, args...) \
+       usbip_dbg_with_flag(usbip_debug_stub_tx, fmt , ##args)
+
+/*
+ * USB/IP request headers
+ *
+ * Each request is transferred across the network to its counterpart, which
+ * facilitates the normal USB communication. The values contained in the headers
+ * are basically the same as in a URB. Currently, four request types are
+ * defined:
+ *
+ *  - USBIP_CMD_SUBMIT: a USB request block, corresponds to usb_submit_urb()
+ *    (client to server)
+ *
+ *  - USBIP_RET_SUBMIT: the result of USBIP_CMD_SUBMIT
+ *    (server to client)
+ *
+ *  - USBIP_CMD_UNLINK: an unlink request of a pending USBIP_CMD_SUBMIT,
+ *    corresponds to usb_unlink_urb()
+ *    (client to server)
+ *
+ *  - USBIP_RET_UNLINK: the result of USBIP_CMD_UNLINK
+ *    (server to client)
+ *
+ */
+#define USBIP_CMD_SUBMIT       0x0001
+#define USBIP_CMD_UNLINK       0x0002
+#define USBIP_RET_SUBMIT       0x0003
+#define USBIP_RET_UNLINK       0x0004
+
+#define USBIP_DIR_OUT  0x00
+#define USBIP_DIR_IN   0x01
+
+/**
+ * struct usbip_header_basic - data pertinent to every request
+ * @command: the usbip request type
+ * @seqnum: sequential number that identifies requests; incremented per
+ *         connection
+ * @devid: specifies a remote USB device uniquely instead of busnum and devnum;
+ *        in the stub driver, this value is ((busnum << 16) | devnum)
+ * @direction: direction of the transfer
+ * @ep: endpoint number
+ */
+struct usbip_header_basic {
+       __u32 command;
+       __u32 seqnum;
+       __u32 devid;
+       __u32 direction;
+       __u32 ep;
+} __packed;
+
+/**
+ * struct usbip_header_cmd_submit - USBIP_CMD_SUBMIT packet header
+ * @transfer_flags: URB flags
+ * @transfer_buffer_length: the data size for (in) or (out) transfer
+ * @start_frame: initial frame for isochronous or interrupt transfers
+ * @number_of_packets: number of isochronous packets
+ * @interval: maximum time for the request on the server-side host controller
+ * @setup: setup data for a control request
+ */
+struct usbip_header_cmd_submit {
+       __u32 transfer_flags;
+       __s32 transfer_buffer_length;
+
+       /* it is difficult for usbip to sync frames (reserved only?) */
+       __s32 start_frame;
+       __s32 number_of_packets;
+       __s32 interval;
+
+       unsigned char setup[8];
+} __packed;
+
+/**
+ * struct usbip_header_ret_submit - USBIP_RET_SUBMIT packet header
+ * @status: return status of a non-iso request
+ * @actual_length: number of bytes transferred
+ * @start_frame: initial frame for isochronous or interrupt transfers
+ * @number_of_packets: number of isochronous packets
+ * @error_count: number of errors for isochronous transfers
+ */
+struct usbip_header_ret_submit {
+       __s32 status;
+       __s32 actual_length;
+       __s32 start_frame;
+       __s32 number_of_packets;
+       __s32 error_count;
+} __packed;
+
+/**
+ * struct usbip_header_cmd_unlink - USBIP_CMD_UNLINK packet header
+ * @seqnum: the URB seqnum to unlink
+ */
+struct usbip_header_cmd_unlink {
+       __u32 seqnum;
+} __packed;
+
+/**
+ * struct usbip_header_ret_unlink - USBIP_RET_UNLINK packet header
+ * @status: return status of the request
+ */
+struct usbip_header_ret_unlink {
+       __s32 status;
+} __packed;
+
+/**
+ * struct usbip_header - common header for all usbip packets
+ * @base: the basic header
+ * @u: packet type dependent header
+ */
+struct usbip_header {
+       struct usbip_header_basic base;
+
+       union {
+               struct usbip_header_cmd_submit  cmd_submit;
+               struct usbip_header_ret_submit  ret_submit;
+               struct usbip_header_cmd_unlink  cmd_unlink;
+               struct usbip_header_ret_unlink  ret_unlink;
+       } u;
+} __packed;
+
+/*
+ * This is the same as usb_iso_packet_descriptor but packed for pdu.
+ */
+struct usbip_iso_packet_descriptor {
+       __u32 offset;
+       __u32 length;                   /* expected length */
+       __u32 actual_length;
+       __u32 status;
+} __packed;
+
+enum usbip_side {
+       USBIP_VHCI,
+       USBIP_STUB,
+};
+
+/* event handler */
+#define USBIP_EH_SHUTDOWN      (1 << 0)
+#define USBIP_EH_BYE           (1 << 1)
+#define USBIP_EH_RESET         (1 << 2)
+#define USBIP_EH_UNUSABLE      (1 << 3)
+
+#define SDEV_EVENT_REMOVED   (USBIP_EH_SHUTDOWN | USBIP_EH_RESET | USBIP_EH_BYE)
+#define        SDEV_EVENT_DOWN         (USBIP_EH_SHUTDOWN | USBIP_EH_RESET)
+#define        SDEV_EVENT_ERROR_TCP    (USBIP_EH_SHUTDOWN | USBIP_EH_RESET)
+#define        SDEV_EVENT_ERROR_SUBMIT (USBIP_EH_SHUTDOWN | USBIP_EH_RESET)
+#define        SDEV_EVENT_ERROR_MALLOC (USBIP_EH_SHUTDOWN | USBIP_EH_UNUSABLE)
+
+#define        VDEV_EVENT_REMOVED      (USBIP_EH_SHUTDOWN | USBIP_EH_BYE)
+#define        VDEV_EVENT_DOWN         (USBIP_EH_SHUTDOWN | USBIP_EH_RESET)
+#define        VDEV_EVENT_ERROR_TCP    (USBIP_EH_SHUTDOWN | USBIP_EH_RESET)
+#define        VDEV_EVENT_ERROR_MALLOC (USBIP_EH_SHUTDOWN | USBIP_EH_UNUSABLE)
+
+/* a common structure for stub_device and vhci_device */
+struct usbip_device {
+       enum usbip_side side;
+       enum usbip_device_status status;
+
+       /* lock for status */
+       spinlock_t lock;
+
+       struct socket *tcp_socket;
+
+       struct task_struct *tcp_rx;
+       struct task_struct *tcp_tx;
+
+       unsigned long event;
+       struct task_struct *eh;
+       wait_queue_head_t eh_waitq;
+
+       struct eh_ops {
+               void (*shutdown)(struct usbip_device *);
+               void (*reset)(struct usbip_device *);
+               void (*unusable)(struct usbip_device *);
+       } eh_ops;
+};
+
+#define kthread_get_run(threadfn, data, namefmt, ...)                     \
+({                                                                        \
+       struct task_struct *__k                                            \
+               = kthread_create(threadfn, data, namefmt, ## __VA_ARGS__); \
+       if (!IS_ERR(__k)) {                                                \
+               get_task_struct(__k);                                      \
+               wake_up_process(__k);                                      \
+       }                                                                  \
+       __k;                                                               \
+})
+
+#define kthread_stop_put(k)            \
+       do {                            \
+               kthread_stop(k);        \
+               put_task_struct(k);     \
+       } while (0)
+
+/* usbip_common.c */
+void usbip_dump_urb(struct urb *purb);
+void usbip_dump_header(struct usbip_header *pdu);
+
+int usbip_recv(struct socket *sock, void *buf, int size);
+
+void usbip_pack_pdu(struct usbip_header *pdu, struct urb *urb, int cmd,
+                   int pack);
+void usbip_header_correct_endian(struct usbip_header *pdu, int send);
+
+struct usbip_iso_packet_descriptor*
+usbip_alloc_iso_desc_pdu(struct urb *urb, ssize_t *bufflen);
+
+/* some members of urb must be substituted before. */
+int usbip_recv_iso(struct usbip_device *ud, struct urb *urb);
+void usbip_pad_iso(struct usbip_device *ud, struct urb *urb);
+int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb);
+
+/* usbip_event.c */
+int usbip_start_eh(struct usbip_device *ud);
+void usbip_stop_eh(struct usbip_device *ud);
+void usbip_event_add(struct usbip_device *ud, unsigned long event);
+int usbip_event_happened(struct usbip_device *ud);
+
+static inline int interface_to_busnum(struct usb_interface *interface)
+{
+       struct usb_device *udev = interface_to_usbdev(interface);
+
+       return udev->bus->busnum;
+}
+
+static inline int interface_to_devnum(struct usb_interface *interface)
+{
+       struct usb_device *udev = interface_to_usbdev(interface);
+
+       return udev->devnum;
+}
+
+#endif /* __USBIP_COMMON_H */
diff --git a/drivers/usb/usbip/usbip_event.c b/drivers/usb/usbip/usbip_event.c
new file mode 100644 (file)
index 0000000..64933b9
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2003-2008 Takahiro Hirofuchi
+ *
+ * This 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 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/kthread.h>
+#include <linux/export.h>
+
+#include "usbip_common.h"
+
+static int event_handler(struct usbip_device *ud)
+{
+       usbip_dbg_eh("enter\n");
+
+       /*
+        * Events are handled by only this thread.
+        */
+       while (usbip_event_happened(ud)) {
+               usbip_dbg_eh("pending event %lx\n", ud->event);
+
+               /*
+                * NOTE: shutdown must come first.
+                * Shutdown the device.
+                */
+               if (ud->event & USBIP_EH_SHUTDOWN) {
+                       ud->eh_ops.shutdown(ud);
+                       ud->event &= ~USBIP_EH_SHUTDOWN;
+               }
+
+               /* Reset the device. */
+               if (ud->event & USBIP_EH_RESET) {
+                       ud->eh_ops.reset(ud);
+                       ud->event &= ~USBIP_EH_RESET;
+               }
+
+               /* Mark the device as unusable. */
+               if (ud->event & USBIP_EH_UNUSABLE) {
+                       ud->eh_ops.unusable(ud);
+                       ud->event &= ~USBIP_EH_UNUSABLE;
+               }
+
+               /* Stop the error handler. */
+               if (ud->event & USBIP_EH_BYE)
+                       return -1;
+       }
+
+       return 0;
+}
+
+static int event_handler_loop(void *data)
+{
+       struct usbip_device *ud = data;
+
+       while (!kthread_should_stop()) {
+               wait_event_interruptible(ud->eh_waitq,
+                                        usbip_event_happened(ud) ||
+                                        kthread_should_stop());
+               usbip_dbg_eh("wakeup\n");
+
+               if (event_handler(ud) < 0)
+                       break;
+       }
+
+       return 0;
+}
+
+int usbip_start_eh(struct usbip_device *ud)
+{
+       init_waitqueue_head(&ud->eh_waitq);
+       ud->event = 0;
+
+       ud->eh = kthread_run(event_handler_loop, ud, "usbip_eh");
+       if (IS_ERR(ud->eh)) {
+               pr_warn("Unable to start control thread\n");
+               return PTR_ERR(ud->eh);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(usbip_start_eh);
+
+void usbip_stop_eh(struct usbip_device *ud)
+{
+       if (ud->eh == current)
+               return; /* do not wait for myself */
+
+       kthread_stop(ud->eh);
+       usbip_dbg_eh("usbip_eh has finished\n");
+}
+EXPORT_SYMBOL_GPL(usbip_stop_eh);
+
+void usbip_event_add(struct usbip_device *ud, unsigned long event)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ud->lock, flags);
+       ud->event |= event;
+       wake_up(&ud->eh_waitq);
+       spin_unlock_irqrestore(&ud->lock, flags);
+}
+EXPORT_SYMBOL_GPL(usbip_event_add);
+
+int usbip_event_happened(struct usbip_device *ud)
+{
+       int happened = 0;
+
+       spin_lock(&ud->lock);
+       if (ud->event != 0)
+               happened = 1;
+       spin_unlock(&ud->lock);
+
+       return happened;
+}
+EXPORT_SYMBOL_GPL(usbip_event_happened);
diff --git a/drivers/usb/usbip/usbip_protocol.txt b/drivers/usb/usbip/usbip_protocol.txt
new file mode 100644 (file)
index 0000000..16b6fe2
--- /dev/null
@@ -0,0 +1,358 @@
+PRELIMINARY DRAFT, MAY CONTAIN MISTAKES!
+28 Jun 2011
+
+The USB/IP protocol follows a server/client architecture. The server exports the
+USB devices and the clients imports them. The device driver for the exported
+USB device runs on the client machine.
+
+The client may ask for the list of the exported USB devices. To get the list the
+client opens a TCP/IP connection towards the server, and sends an OP_REQ_DEVLIST
+packet on top of the TCP/IP connection (so the actual OP_REQ_DEVLIST may be sent
+in one or more pieces at the low level transport layer). The server sends back
+the OP_REP_DEVLIST packet which lists the exported USB devices. Finally the
+TCP/IP connection is closed.
+
+ virtual host controller                                 usb host
+      "client"                                           "server"
+  (imports USB devices)                             (exports USB devices)
+          |                                                 |
+          |                  OP_REQ_DEVLIST                 |
+          | ----------------------------------------------> |
+          |                                                 |
+          |                  OP_REP_DEVLIST                 |
+          | <---------------------------------------------- |
+          |                                                 |
+
+Once the client knows the list of exported USB devices it may decide to use one
+of them. First the client opens a TCP/IP connection towards the server and
+sends an OP_REQ_IMPORT packet. The server replies with OP_REP_IMPORT. If the
+import was successful the TCP/IP connection remains open and will be used
+to transfer the URB traffic between the client and the server. The client may
+send two types of packets: the USBIP_CMD_SUBMIT to submit an URB, and
+USBIP_CMD_UNLINK to unlink a previously submitted URB. The answers of the
+server may be USBIP_RET_SUBMIT and USBIP_RET_UNLINK respectively.
+
+ virtual host controller                                 usb host
+      "client"                                           "server"
+  (imports USB devices)                             (exports USB devices)
+          |                                                 |
+          |                  OP_REQ_IMPORT                  |
+          | ----------------------------------------------> |
+          |                                                 |
+          |                  OP_REP_IMPORT                  |
+          | <---------------------------------------------- |
+          |                                                 |
+          |                                                 |
+          |            USBIP_CMD_SUBMIT(seqnum = n)         |
+          | ----------------------------------------------> |
+          |                                                 |
+          |            USBIP_RET_SUBMIT(seqnum = n)         |
+          | <---------------------------------------------- |
+          |                        .                        |
+          |                        :                        |
+          |                                                 |
+          |            USBIP_CMD_SUBMIT(seqnum = m)         |
+          | ----------------------------------------------> |
+          |                                                 |
+          |            USBIP_CMD_SUBMIT(seqnum = m+1)       |
+          | ----------------------------------------------> |
+          |                                                 |
+          |            USBIP_CMD_SUBMIT(seqnum = m+2)       |
+          | ----------------------------------------------> |
+          |                                                 |
+          |            USBIP_RET_SUBMIT(seqnum = m)         |
+          | <---------------------------------------------- |
+          |                                                 |
+          |            USBIP_CMD_SUBMIT(seqnum = m+3)       |
+          | ----------------------------------------------> |
+          |                                                 |
+          |            USBIP_RET_SUBMIT(seqnum = m+1)       |
+          | <---------------------------------------------- |
+          |                                                 |
+          |            USBIP_CMD_SUBMIT(seqnum = m+4)       |
+          | ----------------------------------------------> |
+          |                                                 |
+          |            USBIP_RET_SUBMIT(seqnum = m+2)       |
+          | <---------------------------------------------- |
+          |                        .                        |
+          |                        :                        |
+          |                                                 |
+          |               USBIP_CMD_UNLINK                  |
+          | ----------------------------------------------> |
+          |                                                 |
+          |               USBIP_RET_UNLINK                  |
+          | <---------------------------------------------- |
+          |                                                 |
+
+The fields are in network (big endian) byte order meaning that the most significant
+byte (MSB) is stored at the lowest address.
+
+
+OP_REQ_DEVLIST: Retrieve the list of exported USB devices.
+
+ Offset    | Length | Value      | Description
+-----------+--------+------------+---------------------------------------------------
+ 0         | 2      | 0x0100     | Binary-coded decimal USBIP version number: v1.0.0
+-----------+--------+------------+---------------------------------------------------
+ 2         | 2      | 0x8005     | Command code: Retrieve the list of exported USB
+           |        |            |   devices.
+-----------+--------+------------+---------------------------------------------------
+ 4         | 4      | 0x00000000 | Status: unused, shall be set to 0
+
+OP_REP_DEVLIST: Reply with the list of exported USB devices.
+
+ Offset    | Length | Value      | Description
+-----------+--------+------------+---------------------------------------------------
+ 0         | 2      | 0x0100     | Binary-coded decimal USBIP version number: v1.0.0.
+-----------+--------+------------+---------------------------------------------------
+ 2         | 2      | 0x0005     | Reply code: The list of exported USB devices.
+-----------+--------+------------+---------------------------------------------------
+ 4         | 4      | 0x00000000 | Status: 0 for OK
+-----------+--------+------------+---------------------------------------------------
+ 8         | 4      | n          | Number of exported devices: 0 means no exported
+           |        |            |   devices.
+-----------+--------+------------+---------------------------------------------------
+ 0x0C      |        |            | From now on the exported n devices are described,
+           |        |            |   if any. If no devices are exported the message
+           |        |            |   ends with the previous "number of exported
+           |        |            |   devices" field.
+-----------+--------+------------+---------------------------------------------------
+           | 256    |            | path: Path of the device on the host exporting the
+           |        |            |   USB device, string closed with zero byte, e.g.
+           |        |            |   "/sys/devices/pci0000:00/0000:00:1d.1/usb3/3-2"
+           |        |            |   The unused bytes shall be filled with zero
+           |        |            |   bytes.
+-----------+--------+------------+---------------------------------------------------
+ 0x10C     | 32     |            | busid: Bus ID of the exported device, string
+           |        |            |   closed with zero byte, e.g. "3-2". The unused
+           |        |            |   bytes shall be filled with zero bytes.
+-----------+--------+------------+---------------------------------------------------
+ 0x12C     | 4      |            | busnum
+-----------+--------+------------+---------------------------------------------------
+ 0x130     | 4      |            | devnum
+-----------+--------+------------+---------------------------------------------------
+ 0x134     | 4      |            | speed
+-----------+--------+------------+---------------------------------------------------
+ 0x138     | 2      |            | idVendor
+-----------+--------+------------+---------------------------------------------------
+ 0x13A     | 2      |            | idProduct
+-----------+--------+------------+---------------------------------------------------
+ 0x13C     | 2      |            | bcdDevice
+-----------+--------+------------+---------------------------------------------------
+ 0x13E     | 1      |            | bDeviceClass
+-----------+--------+------------+---------------------------------------------------
+ 0x13F     | 1      |            | bDeviceSubClass
+-----------+--------+------------+---------------------------------------------------
+ 0x140     | 1      |            | bDeviceProtocol
+-----------+--------+------------+---------------------------------------------------
+ 0x141     | 1      |            | bConfigurationValue
+-----------+--------+------------+---------------------------------------------------
+ 0x142     | 1      |            | bNumConfigurations
+-----------+--------+------------+---------------------------------------------------
+ 0x143     | 1      |            | bNumInterfaces
+-----------+--------+------------+---------------------------------------------------
+ 0x144     |        | m_0        | From now on each interface is described, all
+           |        |            |   together bNumInterfaces times, with the
+           |        |            |   the following 4 fields:
+-----------+--------+------------+---------------------------------------------------
+           | 1      |            | bInterfaceClass
+-----------+--------+------------+---------------------------------------------------
+ 0x145     | 1      |            | bInterfaceSubClass
+-----------+--------+------------+---------------------------------------------------
+ 0x146     | 1      |            | bInterfaceProtocol
+-----------+--------+------------+---------------------------------------------------
+ 0x147     | 1      |            | padding byte for alignment, shall be set to zero
+-----------+--------+------------+---------------------------------------------------
+ 0xC +     |        |            | The second exported USB device starts at i=1
+ i*0x138 + |        |            | with the busid field.
+ m_(i-1)*4 |        |            |
+
+OP_REQ_IMPORT: Request to import (attach) a remote USB device.
+
+ Offset    | Length | Value      | Description
+-----------+--------+------------+---------------------------------------------------
+ 0         | 2      | 0x0100     | Binary-coded decimal USBIP version number: v1.0.0
+-----------+--------+------------+---------------------------------------------------
+ 2         | 2      | 0x8003     | Command code: import a remote USB device.
+-----------+--------+------------+---------------------------------------------------
+ 4         | 4      | 0x00000000 | Status: unused, shall be set to 0
+-----------+--------+------------+---------------------------------------------------
+ 8         | 32     |            | busid: the busid of the exported device on the
+           |        |            |   remote host. The possible values are taken
+           |        |            |   from the message field OP_REP_DEVLIST.busid.
+           |        |            |   A string closed with zero, the unused bytes
+           |        |            |   shall be filled with zeros.
+-----------+--------+------------+---------------------------------------------------
+
+OP_REP_IMPORT: Reply to import (attach) a remote USB device.
+
+ Offset    | Length | Value      | Description
+-----------+--------+------------+---------------------------------------------------
+ 0         | 2      | 0x0100     | Binary-coded decimal USBIP version number: v1.0.0
+-----------+--------+------------+---------------------------------------------------
+ 2         | 2      | 0x0003     | Reply code: Reply to import.
+-----------+--------+------------+---------------------------------------------------
+ 4         | 4      | 0x00000000 | Status: 0 for OK
+           |        |            |         1 for error
+-----------+--------+------------+---------------------------------------------------
+ 8         |        |            | From now on comes the details of the imported
+           |        |            |   device, if the previous status field was OK (0),
+           |        |            |   otherwise the reply ends with the status field.
+-----------+--------+------------+---------------------------------------------------
+           | 256    |            | path: Path of the device on the host exporting the
+           |        |            |   USB device, string closed with zero byte, e.g.
+           |        |            |   "/sys/devices/pci0000:00/0000:00:1d.1/usb3/3-2"
+           |        |            |   The unused bytes shall be filled with zero
+           |        |            |   bytes.
+-----------+--------+------------+---------------------------------------------------
+ 0x108     | 32     |            | busid: Bus ID of the exported device, string
+           |        |            |   closed with zero byte, e.g. "3-2". The unused
+           |        |            |   bytes shall be filled with zero bytes.
+-----------+--------+------------+---------------------------------------------------
+ 0x128     | 4      |            | busnum
+-----------+--------+------------+---------------------------------------------------
+ 0x12C     | 4      |            | devnum
+-----------+--------+------------+---------------------------------------------------
+ 0x130     | 4      |            | speed
+-----------+--------+------------+---------------------------------------------------
+ 0x134     | 2      |            | idVendor
+-----------+--------+------------+---------------------------------------------------
+ 0x136     | 2      |            | idProduct
+-----------+--------+------------+---------------------------------------------------
+ 0x138     | 2      |            | bcdDevice
+-----------+--------+------------+---------------------------------------------------
+ 0x139     | 1      |            | bDeviceClass
+-----------+--------+------------+---------------------------------------------------
+ 0x13A     | 1      |            | bDeviceSubClass
+-----------+--------+------------+---------------------------------------------------
+ 0x13B     | 1      |            | bDeviceProtocol
+-----------+--------+------------+---------------------------------------------------
+ 0x13C     | 1      |            | bConfigurationValue
+-----------+--------+------------+---------------------------------------------------
+ 0x13D     | 1      |            | bNumConfigurations
+-----------+--------+------------+---------------------------------------------------
+ 0x13E     | 1      |            | bNumInterfaces
+
+USBIP_CMD_SUBMIT: Submit an URB
+
+ Offset    | Length | Value      | Description
+-----------+--------+------------+---------------------------------------------------
+ 0         | 4      | 0x00000001 | command: Submit an URB
+-----------+--------+------------+---------------------------------------------------
+ 4         | 4      |            | seqnum: the sequence number of the URB to submit
+-----------+--------+------------+---------------------------------------------------
+ 8         | 4      |            | devid
+-----------+--------+------------+---------------------------------------------------
+ 0xC       | 4      |            | direction: 0: USBIP_DIR_OUT
+           |        |            |            1: USBIP_DIR_IN
+-----------+--------+------------+---------------------------------------------------
+ 0x10      | 4      |            | ep: endpoint number, possible values are: 0...15
+-----------+--------+------------+---------------------------------------------------
+ 0x14      | 4      |            | transfer_flags: possible values depend on the
+           |        |            |   URB transfer type, see below
+-----------+--------+------------+---------------------------------------------------
+ 0x18      | 4      |            | transfer_buffer_length
+-----------+--------+------------+---------------------------------------------------
+ 0x1C      | 4      |            | start_frame: specify the selected frame to
+           |        |            |   transmit an ISO frame, ignored if URB_ISO_ASAP
+           |        |            |   is specified at transfer_flags
+-----------+--------+------------+---------------------------------------------------
+ 0x20      | 4      |            | number_of_packets: number of ISO packets
+-----------+--------+------------+---------------------------------------------------
+ 0x24      | 4      |            | interval: maximum time for the request on the
+           |        |            |   server-side host controller
+-----------+--------+------------+---------------------------------------------------
+ 0x28      | 8      |            | setup: data bytes for USB setup, filled with
+           |        |            |   zeros if not used
+-----------+--------+------------+---------------------------------------------------
+ 0x30      |        |            | URB data. For ISO transfers the padding between
+           |        |            |   each ISO packets is not transmitted.
+
+
+  Allowed transfer_flags  | value      | control | interrupt | bulk     | isochronous
+ -------------------------+------------+---------+-----------+----------+-------------
+  URB_SHORT_NOT_OK        | 0x00000001 | only in | only in   | only in  | no
+  URB_ISO_ASAP            | 0x00000002 | no      | no        | no       | yes
+  URB_NO_TRANSFER_DMA_MAP | 0x00000004 | yes     | yes       | yes      | yes
+  URB_NO_FSBR             | 0x00000020 | yes     | no        | no       | no
+  URB_ZERO_PACKET         | 0x00000040 | no      | no        | only out | no
+  URB_NO_INTERRUPT        | 0x00000080 | yes     | yes       | yes      | yes
+  URB_FREE_BUFFER         | 0x00000100 | yes     | yes       | yes      | yes
+  URB_DIR_MASK            | 0x00000200 | yes     | yes       | yes      | yes
+
+
+USBIP_RET_SUBMIT: Reply for submitting an URB
+
+ Offset    | Length | Value      | Description
+-----------+--------+------------+---------------------------------------------------
+ 0         | 4      | 0x00000003 | command
+-----------+--------+------------+---------------------------------------------------
+ 4         | 4      |            | seqnum: URB sequence number
+-----------+--------+------------+---------------------------------------------------
+ 8         | 4      |            | devid
+-----------+--------+------------+---------------------------------------------------
+ 0xC       | 4      |            | direction: 0: USBIP_DIR_OUT
+           |        |            |            1: USBIP_DIR_IN
+-----------+--------+------------+---------------------------------------------------
+ 0x10      | 4      |            | ep: endpoint number
+-----------+--------+------------+---------------------------------------------------
+ 0x14      | 4      |            | status: zero for successful URB transaction,
+           |        |            |   otherwise some kind of error happened.
+-----------+--------+------------+---------------------------------------------------
+ 0x18      | 4      | n          | actual_length: number of URB data bytes
+-----------+--------+------------+---------------------------------------------------
+ 0x1C      | 4      |            | start_frame: for an ISO frame the actually
+           |        |            |   selected frame for transmit.
+-----------+--------+------------+---------------------------------------------------
+ 0x20      | 4      |            | number_of_packets
+-----------+--------+------------+---------------------------------------------------
+ 0x24      | 4      |            | error_count
+-----------+--------+------------+---------------------------------------------------
+ 0x28      | 8      |            | setup: data bytes for USB setup, filled with
+           |        |            |   zeros if not used
+-----------+--------+------------+---------------------------------------------------
+ 0x30      | n      |            | URB data bytes. For ISO transfers the padding
+           |        |            |   between each ISO packets is not transmitted.
+
+USBIP_CMD_UNLINK: Unlink an URB
+
+ Offset    | Length | Value      | Description
+-----------+--------+------------+---------------------------------------------------
+ 0         | 4      | 0x00000002 | command: URB unlink command
+-----------+--------+------------+---------------------------------------------------
+ 4         | 4      |            | seqnum: URB sequence number to unlink: FIXME: is this so?
+-----------+--------+------------+---------------------------------------------------
+ 8         | 4      |            | devid
+-----------+--------+------------+---------------------------------------------------
+ 0xC       | 4      |            | direction: 0: USBIP_DIR_OUT
+           |        |            |            1: USBIP_DIR_IN
+-----------+--------+------------+---------------------------------------------------
+ 0x10      | 4      |            | ep: endpoint number: zero
+-----------+--------+------------+---------------------------------------------------
+ 0x14      | 4      |            | seqnum: the URB sequence number given previously
+           |        |            |   at USBIP_CMD_SUBMIT.seqnum field
+-----------+--------+------------+---------------------------------------------------
+ 0x30      | n      |            | URB data bytes. For ISO transfers the padding
+           |        |            |   between each ISO packets is not transmitted.
+
+USBIP_RET_UNLINK: Reply for URB unlink
+
+ Offset    | Length | Value      | Description
+-----------+--------+------------+---------------------------------------------------
+ 0         | 4      | 0x00000004 | command: reply for the URB unlink command
+-----------+--------+------------+---------------------------------------------------
+ 4         | 4      |            | seqnum: the unlinked URB sequence number
+-----------+--------+------------+---------------------------------------------------
+ 8         | 4      |            | devid
+-----------+--------+------------+---------------------------------------------------
+ 0xC       | 4      |            | direction: 0: USBIP_DIR_OUT
+           |        |            |            1: USBIP_DIR_IN
+-----------+--------+------------+---------------------------------------------------
+ 0x10      | 4      |            | ep: endpoint number
+-----------+--------+------------+---------------------------------------------------
+ 0x14      | 4      |            | status: This is the value contained in the
+           |        |            |   urb->status in the URB completition handler.
+           |        |            |   FIXME: a better explanation needed.
+-----------+--------+------------+---------------------------------------------------
+ 0x30      | n      |            | URB data bytes. For ISO transfers the padding
+           |        |            |   between each ISO packets is not transmitted.
diff --git a/drivers/usb/usbip/vhci.h b/drivers/usb/usbip/vhci.h
new file mode 100644 (file)
index 0000000..a863a98
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2003-2008 Takahiro Hirofuchi
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#ifndef __USBIP_VHCI_H
+#define __USBIP_VHCI_H
+
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include <linux/wait.h>
+
+struct vhci_device {
+       struct usb_device *udev;
+
+       /*
+        * devid specifies a remote usb device uniquely instead
+        * of combination of busnum and devnum.
+        */
+       __u32 devid;
+
+       /* speed of a remote device */
+       enum usb_device_speed speed;
+
+       /* vhci root-hub port to which this device is attached */
+       __u32 rhport;
+
+       struct usbip_device ud;
+
+       /* lock for the below link lists */
+       spinlock_t priv_lock;
+
+       /* vhci_priv is linked to one of them. */
+       struct list_head priv_tx;
+       struct list_head priv_rx;
+
+       /* vhci_unlink is linked to one of them */
+       struct list_head unlink_tx;
+       struct list_head unlink_rx;
+
+       /* vhci_tx thread sleeps for this queue */
+       wait_queue_head_t waitq_tx;
+};
+
+/* urb->hcpriv, use container_of() */
+struct vhci_priv {
+       unsigned long seqnum;
+       struct list_head list;
+
+       struct vhci_device *vdev;
+       struct urb *urb;
+};
+
+struct vhci_unlink {
+       /* seqnum of this request */
+       unsigned long seqnum;
+
+       struct list_head list;
+
+       /* seqnum of the unlink target */
+       unsigned long unlink_seqnum;
+};
+
+/* Number of supported ports. Value has an upperbound of USB_MAXCHILDREN */
+#define VHCI_NPORTS 8
+
+/* for usb_bus.hcpriv */
+struct vhci_hcd {
+       spinlock_t lock;
+
+       u32 port_status[VHCI_NPORTS];
+
+       unsigned resuming:1;
+       unsigned long re_timeout;
+
+       atomic_t seqnum;
+
+       /*
+        * NOTE:
+        * wIndex shows the port number and begins from 1.
+        * But, the index of this array begins from 0.
+        */
+       struct vhci_device vdev[VHCI_NPORTS];
+};
+
+extern struct vhci_hcd *the_controller;
+extern const struct attribute_group dev_attr_group;
+
+/* vhci_hcd.c */
+void rh_port_connect(int rhport, enum usb_device_speed speed);
+
+/* vhci_rx.c */
+struct urb *pickup_urb_and_free_priv(struct vhci_device *vdev, __u32 seqnum);
+int vhci_rx_loop(void *data);
+
+/* vhci_tx.c */
+int vhci_tx_loop(void *data);
+
+static inline struct vhci_device *port_to_vdev(__u32 port)
+{
+       return &the_controller->vdev[port];
+}
+
+static inline struct vhci_hcd *hcd_to_vhci(struct usb_hcd *hcd)
+{
+       return (struct vhci_hcd *) (hcd->hcd_priv);
+}
+
+static inline struct usb_hcd *vhci_to_hcd(struct vhci_hcd *vhci)
+{
+       return container_of((void *) vhci, struct usb_hcd, hcd_priv);
+}
+
+static inline struct device *vhci_dev(struct vhci_hcd *vhci)
+{
+       return vhci_to_hcd(vhci)->self.controller;
+}
+
+#endif /* __USBIP_VHCI_H */
diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c
new file mode 100644 (file)
index 0000000..c02374b
--- /dev/null
@@ -0,0 +1,1171 @@
+/*
+ * Copyright (C) 2003-2008 Takahiro Hirofuchi
+ *
+ * This 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 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/init.h>
+#include <linux/file.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "usbip_common.h"
+#include "vhci.h"
+
+#define DRIVER_AUTHOR "Takahiro Hirofuchi"
+#define DRIVER_DESC "USB/IP 'Virtual' Host Controller (VHCI) Driver"
+
+/*
+ * TODO
+ *     - update root hub emulation
+ *     - move the emulation code to userland ?
+ *             porting to other operating systems
+ *             minimize kernel code
+ *     - add suspend/resume code
+ *     - clean up everything
+ */
+
+/* See usb gadget dummy hcd */
+
+static int vhci_hub_status(struct usb_hcd *hcd, char *buff);
+static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
+                           u16 wIndex, char *buff, u16 wLength);
+static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
+                           gfp_t mem_flags);
+static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status);
+static int vhci_start(struct usb_hcd *vhci_hcd);
+static void vhci_stop(struct usb_hcd *hcd);
+static int vhci_get_frame_number(struct usb_hcd *hcd);
+
+static const char driver_name[] = "vhci_hcd";
+static const char driver_desc[] = "USB/IP Virtual Host Controller";
+
+struct vhci_hcd *the_controller;
+
+static const char * const bit_desc[] = {
+       "CONNECTION",           /*0*/
+       "ENABLE",               /*1*/
+       "SUSPEND",              /*2*/
+       "OVER_CURRENT",         /*3*/
+       "RESET",                /*4*/
+       "R5",                   /*5*/
+       "R6",                   /*6*/
+       "R7",                   /*7*/
+       "POWER",                /*8*/
+       "LOWSPEED",             /*9*/
+       "HIGHSPEED",            /*10*/
+       "PORT_TEST",            /*11*/
+       "INDICATOR",            /*12*/
+       "R13",                  /*13*/
+       "R14",                  /*14*/
+       "R15",                  /*15*/
+       "C_CONNECTION",         /*16*/
+       "C_ENABLE",             /*17*/
+       "C_SUSPEND",            /*18*/
+       "C_OVER_CURRENT",       /*19*/
+       "C_RESET",              /*20*/
+       "R21",                  /*21*/
+       "R22",                  /*22*/
+       "R23",                  /*23*/
+       "R24",                  /*24*/
+       "R25",                  /*25*/
+       "R26",                  /*26*/
+       "R27",                  /*27*/
+       "R28",                  /*28*/
+       "R29",                  /*29*/
+       "R30",                  /*30*/
+       "R31",                  /*31*/
+};
+
+static void dump_port_status_diff(u32 prev_status, u32 new_status)
+{
+       int i = 0;
+       u32 bit = 1;
+
+       pr_debug("status prev -> new: %08x -> %08x\n", prev_status, new_status);
+       while (bit) {
+               u32 prev = prev_status & bit;
+               u32 new = new_status & bit;
+               char change;
+
+               if (!prev && new)
+                       change = '+';
+               else if (prev && !new)
+                       change = '-';
+               else
+                       change = ' ';
+
+               if (prev || new)
+                       pr_debug(" %c%s\n", change, bit_desc[i]);
+               bit <<= 1;
+               i++;
+       }
+       pr_debug("\n");
+}
+
+void rh_port_connect(int rhport, enum usb_device_speed speed)
+{
+       usbip_dbg_vhci_rh("rh_port_connect %d\n", rhport);
+
+       spin_lock(&the_controller->lock);
+
+       the_controller->port_status[rhport] |= USB_PORT_STAT_CONNECTION
+               | (1 << USB_PORT_FEAT_C_CONNECTION);
+
+       switch (speed) {
+       case USB_SPEED_HIGH:
+               the_controller->port_status[rhport] |= USB_PORT_STAT_HIGH_SPEED;
+               break;
+       case USB_SPEED_LOW:
+               the_controller->port_status[rhport] |= USB_PORT_STAT_LOW_SPEED;
+               break;
+       default:
+               break;
+       }
+
+       spin_unlock(&the_controller->lock);
+
+       usb_hcd_poll_rh_status(vhci_to_hcd(the_controller));
+}
+
+static void rh_port_disconnect(int rhport)
+{
+       usbip_dbg_vhci_rh("rh_port_disconnect %d\n", rhport);
+
+       spin_lock(&the_controller->lock);
+
+       the_controller->port_status[rhport] &= ~USB_PORT_STAT_CONNECTION;
+       the_controller->port_status[rhport] |=
+                                       (1 << USB_PORT_FEAT_C_CONNECTION);
+
+       spin_unlock(&the_controller->lock);
+       usb_hcd_poll_rh_status(vhci_to_hcd(the_controller));
+}
+
+#define PORT_C_MASK                            \
+       ((USB_PORT_STAT_C_CONNECTION            \
+         | USB_PORT_STAT_C_ENABLE              \
+         | USB_PORT_STAT_C_SUSPEND             \
+         | USB_PORT_STAT_C_OVERCURRENT         \
+         | USB_PORT_STAT_C_RESET) << 16)
+
+/*
+ * Returns 0 if the status hasn't changed, or the number of bytes in buf.
+ * Ports are 0-indexed from the HCD point of view,
+ * and 1-indexed from the USB core pointer of view.
+ *
+ * @buf: a bitmap to show which port status has been changed.
+ *  bit  0: reserved
+ *  bit  1: the status of port 0 has been changed.
+ *  bit  2: the status of port 1 has been changed.
+ *  ...
+ */
+static int vhci_hub_status(struct usb_hcd *hcd, char *buf)
+{
+       struct vhci_hcd *vhci;
+       int             retval;
+       int             rhport;
+       int             changed = 0;
+
+       retval = DIV_ROUND_UP(VHCI_NPORTS + 1, 8);
+       memset(buf, 0, retval);
+
+       vhci = hcd_to_vhci(hcd);
+
+       spin_lock(&vhci->lock);
+       if (!HCD_HW_ACCESSIBLE(hcd)) {
+               usbip_dbg_vhci_rh("hw accessible flag not on?\n");
+               goto done;
+       }
+
+       /* check pseudo status register for each port */
+       for (rhport = 0; rhport < VHCI_NPORTS; rhport++) {
+               if ((vhci->port_status[rhport] & PORT_C_MASK)) {
+                       /* The status of a port has been changed, */
+                       usbip_dbg_vhci_rh("port %d status changed\n", rhport);
+
+                       buf[(rhport + 1) / 8] |= 1 << (rhport + 1) % 8;
+                       changed = 1;
+               }
+       }
+
+       if ((hcd->state == HC_STATE_SUSPENDED) && (changed == 1))
+               usb_hcd_resume_root_hub(hcd);
+
+done:
+       spin_unlock(&vhci->lock);
+       return changed ? retval : 0;
+}
+
+static inline void hub_descriptor(struct usb_hub_descriptor *desc)
+{
+       memset(desc, 0, sizeof(*desc));
+       desc->bDescriptorType = 0x29;
+       desc->bDescLength = 9;
+       desc->wHubCharacteristics = (__constant_cpu_to_le16(0x0001));
+       desc->bNbrPorts = VHCI_NPORTS;
+       desc->u.hs.DeviceRemovable[0] = 0xff;
+       desc->u.hs.DeviceRemovable[1] = 0xff;
+}
+
+static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
+                           u16 wIndex, char *buf, u16 wLength)
+{
+       struct vhci_hcd *dum;
+       int             retval = 0;
+       int             rhport;
+
+       u32 prev_port_status[VHCI_NPORTS];
+
+       if (!HCD_HW_ACCESSIBLE(hcd))
+               return -ETIMEDOUT;
+
+       /*
+        * NOTE:
+        * wIndex shows the port number and begins from 1.
+        */
+       usbip_dbg_vhci_rh("typeReq %x wValue %x wIndex %x\n", typeReq, wValue,
+                         wIndex);
+       if (wIndex > VHCI_NPORTS)
+               pr_err("invalid port number %d\n", wIndex);
+       rhport = ((__u8)(wIndex & 0x00ff)) - 1;
+
+       dum = hcd_to_vhci(hcd);
+
+       spin_lock(&dum->lock);
+
+       /* store old status and compare now and old later */
+       if (usbip_dbg_flag_vhci_rh) {
+               memcpy(prev_port_status, dum->port_status,
+                       sizeof(prev_port_status));
+       }
+
+       switch (typeReq) {
+       case ClearHubFeature:
+               usbip_dbg_vhci_rh(" ClearHubFeature\n");
+               break;
+       case ClearPortFeature:
+               switch (wValue) {
+               case USB_PORT_FEAT_SUSPEND:
+                       if (dum->port_status[rhport] & USB_PORT_STAT_SUSPEND) {
+                               /* 20msec signaling */
+                               dum->resuming = 1;
+                               dum->re_timeout =
+                                       jiffies + msecs_to_jiffies(20);
+                       }
+                       break;
+               case USB_PORT_FEAT_POWER:
+                       usbip_dbg_vhci_rh(
+                               " ClearPortFeature: USB_PORT_FEAT_POWER\n");
+                       dum->port_status[rhport] = 0;
+                       dum->resuming = 0;
+                       break;
+               case USB_PORT_FEAT_C_RESET:
+                       usbip_dbg_vhci_rh(
+                               " ClearPortFeature: USB_PORT_FEAT_C_RESET\n");
+                       switch (dum->vdev[rhport].speed) {
+                       case USB_SPEED_HIGH:
+                               dum->port_status[rhport] |=
+                                       USB_PORT_STAT_HIGH_SPEED;
+                               break;
+                       case USB_SPEED_LOW:
+                               dum->port_status[rhport] |=
+                                       USB_PORT_STAT_LOW_SPEED;
+                               break;
+                       default:
+                               break;
+                       }
+               default:
+                       usbip_dbg_vhci_rh(" ClearPortFeature: default %x\n",
+                                         wValue);
+                       dum->port_status[rhport] &= ~(1 << wValue);
+                       break;
+               }
+               break;
+       case GetHubDescriptor:
+               usbip_dbg_vhci_rh(" GetHubDescriptor\n");
+               hub_descriptor((struct usb_hub_descriptor *) buf);
+               break;
+       case GetHubStatus:
+               usbip_dbg_vhci_rh(" GetHubStatus\n");
+               *(__le32 *) buf = cpu_to_le32(0);
+               break;
+       case GetPortStatus:
+               usbip_dbg_vhci_rh(" GetPortStatus port %x\n", wIndex);
+               if (wIndex > VHCI_NPORTS || wIndex < 1) {
+                       pr_err("invalid port number %d\n", wIndex);
+                       retval = -EPIPE;
+               }
+
+               /* we do not care about resume. */
+
+               /* whoever resets or resumes must GetPortStatus to
+                * complete it!!
+                */
+               if (dum->resuming && time_after(jiffies, dum->re_timeout)) {
+                       dum->port_status[rhport] |=
+                               (1 << USB_PORT_FEAT_C_SUSPEND);
+                       dum->port_status[rhport] &=
+                               ~(1 << USB_PORT_FEAT_SUSPEND);
+                       dum->resuming = 0;
+                       dum->re_timeout = 0;
+               }
+
+               if ((dum->port_status[rhport] & (1 << USB_PORT_FEAT_RESET)) !=
+                   0 && time_after(jiffies, dum->re_timeout)) {
+                       dum->port_status[rhport] |=
+                               (1 << USB_PORT_FEAT_C_RESET);
+                       dum->port_status[rhport] &=
+                               ~(1 << USB_PORT_FEAT_RESET);
+                       dum->re_timeout = 0;
+
+                       if (dum->vdev[rhport].ud.status ==
+                           VDEV_ST_NOTASSIGNED) {
+                               usbip_dbg_vhci_rh(
+                                       " enable rhport %d (status %u)\n",
+                                       rhport,
+                                       dum->vdev[rhport].ud.status);
+                               dum->port_status[rhport] |=
+                                       USB_PORT_STAT_ENABLE;
+                       }
+               }
+               ((__le16 *) buf)[0] = cpu_to_le16(dum->port_status[rhport]);
+               ((__le16 *) buf)[1] =
+                       cpu_to_le16(dum->port_status[rhport] >> 16);
+
+               usbip_dbg_vhci_rh(" GetPortStatus bye %x %x\n", ((u16 *)buf)[0],
+                                 ((u16 *)buf)[1]);
+               break;
+       case SetHubFeature:
+               usbip_dbg_vhci_rh(" SetHubFeature\n");
+               retval = -EPIPE;
+               break;
+       case SetPortFeature:
+               switch (wValue) {
+               case USB_PORT_FEAT_SUSPEND:
+                       usbip_dbg_vhci_rh(
+                               " SetPortFeature: USB_PORT_FEAT_SUSPEND\n");
+                       break;
+               case USB_PORT_FEAT_RESET:
+                       usbip_dbg_vhci_rh(
+                               " SetPortFeature: USB_PORT_FEAT_RESET\n");
+                       /* if it's already running, disconnect first */
+                       if (dum->port_status[rhport] & USB_PORT_STAT_ENABLE) {
+                               dum->port_status[rhport] &=
+                                       ~(USB_PORT_STAT_ENABLE |
+                                         USB_PORT_STAT_LOW_SPEED |
+                                         USB_PORT_STAT_HIGH_SPEED);
+                               /* FIXME test that code path! */
+                       }
+                       /* 50msec reset signaling */
+                       dum->re_timeout = jiffies + msecs_to_jiffies(50);
+
+                       /* FALLTHROUGH */
+               default:
+                       usbip_dbg_vhci_rh(" SetPortFeature: default %d\n",
+                                         wValue);
+                       dum->port_status[rhport] |= (1 << wValue);
+                       break;
+               }
+               break;
+
+       default:
+               pr_err("default: no such request\n");
+
+               /* "protocol stall" on error */
+               retval = -EPIPE;
+       }
+
+       if (usbip_dbg_flag_vhci_rh) {
+               pr_debug("port %d\n", rhport);
+               /* Only dump valid port status */
+               if (rhport >= 0) {
+                       dump_port_status_diff(prev_port_status[rhport],
+                                             dum->port_status[rhport]);
+               }
+       }
+       usbip_dbg_vhci_rh(" bye\n");
+
+       spin_unlock(&dum->lock);
+
+       return retval;
+}
+
+static struct vhci_device *get_vdev(struct usb_device *udev)
+{
+       int i;
+
+       if (!udev)
+               return NULL;
+
+       for (i = 0; i < VHCI_NPORTS; i++)
+               if (the_controller->vdev[i].udev == udev)
+                       return port_to_vdev(i);
+
+       return NULL;
+}
+
+static void vhci_tx_urb(struct urb *urb)
+{
+       struct vhci_device *vdev = get_vdev(urb->dev);
+       struct vhci_priv *priv;
+
+       if (!vdev) {
+               pr_err("could not get virtual device");
+               return;
+       }
+
+       priv = kzalloc(sizeof(struct vhci_priv), GFP_ATOMIC);
+       if (!priv) {
+               usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_MALLOC);
+               return;
+       }
+
+       spin_lock(&vdev->priv_lock);
+
+       priv->seqnum = atomic_inc_return(&the_controller->seqnum);
+       if (priv->seqnum == 0xffff)
+               dev_info(&urb->dev->dev, "seqnum max\n");
+
+       priv->vdev = vdev;
+       priv->urb = urb;
+
+       urb->hcpriv = (void *) priv;
+
+       list_add_tail(&priv->list, &vdev->priv_tx);
+
+       wake_up(&vdev->waitq_tx);
+       spin_unlock(&vdev->priv_lock);
+}
+
+static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
+                           gfp_t mem_flags)
+{
+       struct device *dev = &urb->dev->dev;
+       int ret = 0;
+       struct vhci_device *vdev;
+
+       usbip_dbg_vhci_hc("enter, usb_hcd %p urb %p mem_flags %d\n",
+                         hcd, urb, mem_flags);
+
+       /* patch to usb_sg_init() is in 2.5.60 */
+       BUG_ON(!urb->transfer_buffer && urb->transfer_buffer_length);
+
+       spin_lock(&the_controller->lock);
+
+       if (urb->status != -EINPROGRESS) {
+               dev_err(dev, "URB already unlinked!, status %d\n", urb->status);
+               spin_unlock(&the_controller->lock);
+               return urb->status;
+       }
+
+       vdev = port_to_vdev(urb->dev->portnum-1);
+
+       /* refuse enqueue for dead connection */
+       spin_lock(&vdev->ud.lock);
+       if (vdev->ud.status == VDEV_ST_NULL ||
+           vdev->ud.status == VDEV_ST_ERROR) {
+               dev_err(dev, "enqueue for inactive port %d\n", vdev->rhport);
+               spin_unlock(&vdev->ud.lock);
+               spin_unlock(&the_controller->lock);
+               return -ENODEV;
+       }
+       spin_unlock(&vdev->ud.lock);
+
+       ret = usb_hcd_link_urb_to_ep(hcd, urb);
+       if (ret)
+               goto no_need_unlink;
+
+       /*
+        * The enumeration process is as follows;
+        *
+        *  1. Get_Descriptor request to DevAddrs(0) EndPoint(0)
+        *     to get max packet length of default pipe
+        *
+        *  2. Set_Address request to DevAddr(0) EndPoint(0)
+        *
+        */
+       if (usb_pipedevice(urb->pipe) == 0) {
+               __u8 type = usb_pipetype(urb->pipe);
+               struct usb_ctrlrequest *ctrlreq =
+                       (struct usb_ctrlrequest *) urb->setup_packet;
+
+               if (type != PIPE_CONTROL || !ctrlreq) {
+                       dev_err(dev, "invalid request to devnum 0\n");
+                       ret = -EINVAL;
+                       goto no_need_xmit;
+               }
+
+               switch (ctrlreq->bRequest) {
+               case USB_REQ_SET_ADDRESS:
+                       /* set_address may come when a device is reset */
+                       dev_info(dev, "SetAddress Request (%d) to port %d\n",
+                                ctrlreq->wValue, vdev->rhport);
+
+                       if (vdev->udev)
+                               usb_put_dev(vdev->udev);
+                       vdev->udev = usb_get_dev(urb->dev);
+
+                       spin_lock(&vdev->ud.lock);
+                       vdev->ud.status = VDEV_ST_USED;
+                       spin_unlock(&vdev->ud.lock);
+
+                       if (urb->status == -EINPROGRESS) {
+                               /* This request is successfully completed. */
+                               /* If not -EINPROGRESS, possibly unlinked. */
+                               urb->status = 0;
+                       }
+
+                       goto no_need_xmit;
+
+               case USB_REQ_GET_DESCRIPTOR:
+                       if (ctrlreq->wValue == cpu_to_le16(USB_DT_DEVICE << 8))
+                               usbip_dbg_vhci_hc(
+                                       "Not yet?:Get_Descriptor to device 0 (get max pipe size)\n");
+
+                       if (vdev->udev)
+                               usb_put_dev(vdev->udev);
+                       vdev->udev = usb_get_dev(urb->dev);
+                       goto out;
+
+               default:
+                       /* NOT REACHED */
+                       dev_err(dev,
+                               "invalid request to devnum 0 bRequest %u, wValue %u\n",
+                               ctrlreq->bRequest,
+                               ctrlreq->wValue);
+                       ret =  -EINVAL;
+                       goto no_need_xmit;
+               }
+
+       }
+
+out:
+       vhci_tx_urb(urb);
+       spin_unlock(&the_controller->lock);
+
+       return 0;
+
+no_need_xmit:
+       usb_hcd_unlink_urb_from_ep(hcd, urb);
+no_need_unlink:
+       spin_unlock(&the_controller->lock);
+       usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, urb->status);
+       return ret;
+}
+
+/*
+ * vhci_rx gives back the urb after receiving the reply of the urb.  If an
+ * unlink pdu is sent or not, vhci_rx receives a normal return pdu and gives
+ * back its urb. For the driver unlinking the urb, the content of the urb is
+ * not important, but the calling to its completion handler is important; the
+ * completion of unlinking is notified by the completion handler.
+ *
+ *
+ * CLIENT SIDE
+ *
+ * - When vhci_hcd receives RET_SUBMIT,
+ *
+ *     - case 1a). the urb of the pdu is not unlinking.
+ *             - normal case
+ *             => just give back the urb
+ *
+ *     - case 1b). the urb of the pdu is unlinking.
+ *             - usbip.ko will return a reply of the unlinking request.
+ *             => give back the urb now and go to case 2b).
+ *
+ * - When vhci_hcd receives RET_UNLINK,
+ *
+ *     - case 2a). a submit request is still pending in vhci_hcd.
+ *             - urb was really pending in usbip.ko and urb_unlink_urb() was
+ *               completed there.
+ *             => free a pending submit request
+ *             => notify unlink completeness by giving back the urb
+ *
+ *     - case 2b). a submit request is *not* pending in vhci_hcd.
+ *             - urb was already given back to the core driver.
+ *             => do not give back the urb
+ *
+ *
+ * SERVER SIDE
+ *
+ * - When usbip receives CMD_UNLINK,
+ *
+ *     - case 3a). the urb of the unlink request is now in submission.
+ *             => do usb_unlink_urb().
+ *             => after the unlink is completed, send RET_UNLINK.
+ *
+ *     - case 3b). the urb of the unlink request is not in submission.
+ *             - may be already completed or never be received
+ *             => send RET_UNLINK
+ *
+ */
+static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+{
+       struct vhci_priv *priv;
+       struct vhci_device *vdev;
+
+       pr_info("dequeue a urb %p\n", urb);
+
+       spin_lock(&the_controller->lock);
+
+       priv = urb->hcpriv;
+       if (!priv) {
+               /* URB was never linked! or will be soon given back by
+                * vhci_rx. */
+               spin_unlock(&the_controller->lock);
+               return 0;
+       }
+
+       {
+               int ret = 0;
+
+               ret = usb_hcd_check_unlink_urb(hcd, urb, status);
+               if (ret) {
+                       spin_unlock(&the_controller->lock);
+                       return ret;
+               }
+       }
+
+        /* send unlink request here? */
+       vdev = priv->vdev;
+
+       if (!vdev->ud.tcp_socket) {
+               /* tcp connection is closed */
+               spin_lock(&vdev->priv_lock);
+
+               pr_info("device %p seems to be disconnected\n", vdev);
+               list_del(&priv->list);
+               kfree(priv);
+               urb->hcpriv = NULL;
+
+               spin_unlock(&vdev->priv_lock);
+
+               /*
+                * If tcp connection is alive, we have sent CMD_UNLINK.
+                * vhci_rx will receive RET_UNLINK and give back the URB.
+                * Otherwise, we give back it here.
+                */
+               pr_info("gives back urb %p\n", urb);
+
+               usb_hcd_unlink_urb_from_ep(hcd, urb);
+
+               spin_unlock(&the_controller->lock);
+               usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb,
+                                    urb->status);
+               spin_lock(&the_controller->lock);
+
+       } else {
+               /* tcp connection is alive */
+               struct vhci_unlink *unlink;
+
+               spin_lock(&vdev->priv_lock);
+
+               /* setup CMD_UNLINK pdu */
+               unlink = kzalloc(sizeof(struct vhci_unlink), GFP_ATOMIC);
+               if (!unlink) {
+                       spin_unlock(&vdev->priv_lock);
+                       spin_unlock(&the_controller->lock);
+                       usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_MALLOC);
+                       return -ENOMEM;
+               }
+
+               unlink->seqnum = atomic_inc_return(&the_controller->seqnum);
+               if (unlink->seqnum == 0xffff)
+                       pr_info("seqnum max\n");
+
+               unlink->unlink_seqnum = priv->seqnum;
+
+               pr_info("device %p seems to be still connected\n", vdev);
+
+               /* send cmd_unlink and try to cancel the pending URB in the
+                * peer */
+               list_add_tail(&unlink->list, &vdev->unlink_tx);
+               wake_up(&vdev->waitq_tx);
+
+               spin_unlock(&vdev->priv_lock);
+       }
+
+       spin_unlock(&the_controller->lock);
+
+       usbip_dbg_vhci_hc("leave\n");
+       return 0;
+}
+
+static void vhci_device_unlink_cleanup(struct vhci_device *vdev)
+{
+       struct vhci_unlink *unlink, *tmp;
+
+       spin_lock(&the_controller->lock);
+       spin_lock(&vdev->priv_lock);
+
+       list_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) {
+               pr_info("unlink cleanup tx %lu\n", unlink->unlink_seqnum);
+               list_del(&unlink->list);
+               kfree(unlink);
+       }
+
+       while (!list_empty(&vdev->unlink_rx)) {
+               struct urb *urb;
+
+               unlink = list_first_entry(&vdev->unlink_rx, struct vhci_unlink,
+                       list);
+
+               /* give back URB of unanswered unlink request */
+               pr_info("unlink cleanup rx %lu\n", unlink->unlink_seqnum);
+
+               urb = pickup_urb_and_free_priv(vdev, unlink->unlink_seqnum);
+               if (!urb) {
+                       pr_info("the urb (seqnum %lu) was already given back\n",
+                               unlink->unlink_seqnum);
+                       list_del(&unlink->list);
+                       kfree(unlink);
+                       continue;
+               }
+
+               urb->status = -ENODEV;
+
+               usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb);
+
+               list_del(&unlink->list);
+
+               spin_unlock(&vdev->priv_lock);
+               spin_unlock(&the_controller->lock);
+
+               usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb,
+                                    urb->status);
+
+               spin_lock(&the_controller->lock);
+               spin_lock(&vdev->priv_lock);
+
+               kfree(unlink);
+       }
+
+       spin_unlock(&vdev->priv_lock);
+       spin_unlock(&the_controller->lock);
+}
+
+/*
+ * The important thing is that only one context begins cleanup.
+ * This is why error handling and cleanup become simple.
+ * We do not want to consider race condition as possible.
+ */
+static void vhci_shutdown_connection(struct usbip_device *ud)
+{
+       struct vhci_device *vdev = container_of(ud, struct vhci_device, ud);
+
+       /* need this? see stub_dev.c */
+       if (ud->tcp_socket) {
+               pr_debug("shutdown tcp_socket %p\n", ud->tcp_socket);
+               kernel_sock_shutdown(ud->tcp_socket, SHUT_RDWR);
+       }
+
+       /* kill threads related to this sdev */
+       if (vdev->ud.tcp_rx) {
+               kthread_stop_put(vdev->ud.tcp_rx);
+               vdev->ud.tcp_rx = NULL;
+       }
+       if (vdev->ud.tcp_tx) {
+               kthread_stop_put(vdev->ud.tcp_tx);
+               vdev->ud.tcp_tx = NULL;
+       }
+       pr_info("stop threads\n");
+
+       /* active connection is closed */
+       if (vdev->ud.tcp_socket) {
+               sockfd_put(vdev->ud.tcp_socket);
+               vdev->ud.tcp_socket = NULL;
+       }
+       pr_info("release socket\n");
+
+       vhci_device_unlink_cleanup(vdev);
+
+       /*
+        * rh_port_disconnect() is a trigger of ...
+        *   usb_disable_device():
+        *      disable all the endpoints for a USB device.
+        *   usb_disable_endpoint():
+        *      disable endpoints. pending urbs are unlinked(dequeued).
+        *
+        * NOTE: After calling rh_port_disconnect(), the USB device drivers of a
+        * detached device should release used urbs in a cleanup function (i.e.
+        * xxx_disconnect()). Therefore, vhci_hcd does not need to release
+        * pushed urbs and their private data in this function.
+        *
+        * NOTE: vhci_dequeue() must be considered carefully. When shutting down
+        * a connection, vhci_shutdown_connection() expects vhci_dequeue()
+        * gives back pushed urbs and frees their private data by request of
+        * the cleanup function of a USB driver. When unlinking a urb with an
+        * active connection, vhci_dequeue() does not give back the urb which
+        * is actually given back by vhci_rx after receiving its return pdu.
+        *
+        */
+       rh_port_disconnect(vdev->rhport);
+
+       pr_info("disconnect device\n");
+}
+
+
+static void vhci_device_reset(struct usbip_device *ud)
+{
+       struct vhci_device *vdev = container_of(ud, struct vhci_device, ud);
+
+       spin_lock(&ud->lock);
+
+       vdev->speed  = 0;
+       vdev->devid  = 0;
+
+       if (vdev->udev)
+               usb_put_dev(vdev->udev);
+       vdev->udev = NULL;
+
+       if (ud->tcp_socket) {
+               sockfd_put(ud->tcp_socket);
+               ud->tcp_socket = NULL;
+       }
+       ud->status = VDEV_ST_NULL;
+
+       spin_unlock(&ud->lock);
+}
+
+static void vhci_device_unusable(struct usbip_device *ud)
+{
+       spin_lock(&ud->lock);
+       ud->status = VDEV_ST_ERROR;
+       spin_unlock(&ud->lock);
+}
+
+static void vhci_device_init(struct vhci_device *vdev)
+{
+       memset(vdev, 0, sizeof(*vdev));
+
+       vdev->ud.side   = USBIP_VHCI;
+       vdev->ud.status = VDEV_ST_NULL;
+       spin_lock_init(&vdev->ud.lock);
+
+       INIT_LIST_HEAD(&vdev->priv_rx);
+       INIT_LIST_HEAD(&vdev->priv_tx);
+       INIT_LIST_HEAD(&vdev->unlink_tx);
+       INIT_LIST_HEAD(&vdev->unlink_rx);
+       spin_lock_init(&vdev->priv_lock);
+
+       init_waitqueue_head(&vdev->waitq_tx);
+
+       vdev->ud.eh_ops.shutdown = vhci_shutdown_connection;
+       vdev->ud.eh_ops.reset = vhci_device_reset;
+       vdev->ud.eh_ops.unusable = vhci_device_unusable;
+
+       usbip_start_eh(&vdev->ud);
+}
+
+static int vhci_start(struct usb_hcd *hcd)
+{
+       struct vhci_hcd *vhci = hcd_to_vhci(hcd);
+       int rhport;
+       int err = 0;
+
+       usbip_dbg_vhci_hc("enter vhci_start\n");
+
+       /* initialize private data of usb_hcd */
+
+       for (rhport = 0; rhport < VHCI_NPORTS; rhport++) {
+               struct vhci_device *vdev = &vhci->vdev[rhport];
+
+               vhci_device_init(vdev);
+               vdev->rhport = rhport;
+       }
+
+       atomic_set(&vhci->seqnum, 0);
+       spin_lock_init(&vhci->lock);
+
+       hcd->power_budget = 0; /* no limit */
+       hcd->uses_new_polling = 1;
+
+       /* vhci_hcd is now ready to be controlled through sysfs */
+       err = sysfs_create_group(&vhci_dev(vhci)->kobj, &dev_attr_group);
+       if (err) {
+               pr_err("create sysfs files\n");
+               return err;
+       }
+
+       return 0;
+}
+
+static void vhci_stop(struct usb_hcd *hcd)
+{
+       struct vhci_hcd *vhci = hcd_to_vhci(hcd);
+       int rhport = 0;
+
+       usbip_dbg_vhci_hc("stop VHCI controller\n");
+
+       /* 1. remove the userland interface of vhci_hcd */
+       sysfs_remove_group(&vhci_dev(vhci)->kobj, &dev_attr_group);
+
+       /* 2. shutdown all the ports of vhci_hcd */
+       for (rhport = 0; rhport < VHCI_NPORTS; rhport++) {
+               struct vhci_device *vdev = &vhci->vdev[rhport];
+
+               usbip_event_add(&vdev->ud, VDEV_EVENT_REMOVED);
+               usbip_stop_eh(&vdev->ud);
+       }
+}
+
+static int vhci_get_frame_number(struct usb_hcd *hcd)
+{
+       pr_err("Not yet implemented\n");
+       return 0;
+}
+
+#ifdef CONFIG_PM
+
+/* FIXME: suspend/resume */
+static int vhci_bus_suspend(struct usb_hcd *hcd)
+{
+       struct vhci_hcd *vhci = hcd_to_vhci(hcd);
+
+       dev_dbg(&hcd->self.root_hub->dev, "%s\n", __func__);
+
+       spin_lock(&vhci->lock);
+       hcd->state = HC_STATE_SUSPENDED;
+       spin_unlock(&vhci->lock);
+
+       return 0;
+}
+
+static int vhci_bus_resume(struct usb_hcd *hcd)
+{
+       struct vhci_hcd *vhci = hcd_to_vhci(hcd);
+       int rc = 0;
+
+       dev_dbg(&hcd->self.root_hub->dev, "%s\n", __func__);
+
+       spin_lock(&vhci->lock);
+       if (!HCD_HW_ACCESSIBLE(hcd))
+               rc = -ESHUTDOWN;
+       else
+               hcd->state = HC_STATE_RUNNING;
+       spin_unlock(&vhci->lock);
+
+       return rc;
+}
+
+#else
+
+#define vhci_bus_suspend      NULL
+#define vhci_bus_resume       NULL
+#endif
+
+static struct hc_driver vhci_hc_driver = {
+       .description    = driver_name,
+       .product_desc   = driver_desc,
+       .hcd_priv_size  = sizeof(struct vhci_hcd),
+
+       .flags          = HCD_USB2,
+
+       .start          = vhci_start,
+       .stop           = vhci_stop,
+
+       .urb_enqueue    = vhci_urb_enqueue,
+       .urb_dequeue    = vhci_urb_dequeue,
+
+       .get_frame_number = vhci_get_frame_number,
+
+       .hub_status_data = vhci_hub_status,
+       .hub_control    = vhci_hub_control,
+       .bus_suspend    = vhci_bus_suspend,
+       .bus_resume     = vhci_bus_resume,
+};
+
+static int vhci_hcd_probe(struct platform_device *pdev)
+{
+       struct usb_hcd          *hcd;
+       int                     ret;
+
+       usbip_dbg_vhci_hc("name %s id %d\n", pdev->name, pdev->id);
+
+       /*
+        * Allocate and initialize hcd.
+        * Our private data is also allocated automatically.
+        */
+       hcd = usb_create_hcd(&vhci_hc_driver, &pdev->dev, dev_name(&pdev->dev));
+       if (!hcd) {
+               pr_err("create hcd failed\n");
+               return -ENOMEM;
+       }
+       hcd->has_tt = 1;
+
+       /* this is private data for vhci_hcd */
+       the_controller = hcd_to_vhci(hcd);
+
+       /*
+        * Finish generic HCD structure initialization and register.
+        * Call the driver's reset() and start() routines.
+        */
+       ret = usb_add_hcd(hcd, 0, 0);
+       if (ret != 0) {
+               pr_err("usb_add_hcd failed %d\n", ret);
+               usb_put_hcd(hcd);
+               the_controller = NULL;
+               return ret;
+       }
+
+       usbip_dbg_vhci_hc("bye\n");
+       return 0;
+}
+
+static int vhci_hcd_remove(struct platform_device *pdev)
+{
+       struct usb_hcd  *hcd;
+
+       hcd = platform_get_drvdata(pdev);
+       if (!hcd)
+               return 0;
+
+       /*
+        * Disconnects the root hub,
+        * then reverses the effects of usb_add_hcd(),
+        * invoking the HCD's stop() methods.
+        */
+       usb_remove_hcd(hcd);
+       usb_put_hcd(hcd);
+       the_controller = NULL;
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+
+/* what should happen for USB/IP under suspend/resume? */
+static int vhci_hcd_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct usb_hcd *hcd;
+       int rhport = 0;
+       int connected = 0;
+       int ret = 0;
+
+       hcd = platform_get_drvdata(pdev);
+
+       spin_lock(&the_controller->lock);
+
+       for (rhport = 0; rhport < VHCI_NPORTS; rhport++)
+               if (the_controller->port_status[rhport] &
+                   USB_PORT_STAT_CONNECTION)
+                       connected += 1;
+
+       spin_unlock(&the_controller->lock);
+
+       if (connected > 0) {
+               dev_info(&pdev->dev,
+                        "We have %d active connection%s. Do not suspend.\n",
+                        connected, (connected == 1 ? "" : "s"));
+               ret =  -EBUSY;
+       } else {
+               dev_info(&pdev->dev, "suspend vhci_hcd");
+               clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+       }
+
+       return ret;
+}
+
+static int vhci_hcd_resume(struct platform_device *pdev)
+{
+       struct usb_hcd *hcd;
+
+       dev_dbg(&pdev->dev, "%s\n", __func__);
+
+       hcd = platform_get_drvdata(pdev);
+       set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+       usb_hcd_poll_rh_status(hcd);
+
+       return 0;
+}
+
+#else
+
+#define vhci_hcd_suspend       NULL
+#define vhci_hcd_resume                NULL
+
+#endif
+
+static struct platform_driver vhci_driver = {
+       .probe  = vhci_hcd_probe,
+       .remove = vhci_hcd_remove,
+       .suspend = vhci_hcd_suspend,
+       .resume = vhci_hcd_resume,
+       .driver = {
+               .name = driver_name,
+               .owner = THIS_MODULE,
+       },
+};
+
+/*
+ * The VHCI 'device' is 'virtual'; not a real plug&play hardware.
+ * We need to add this virtual device as a platform device arbitrarily:
+ *     1. platform_device_register()
+ */
+static void the_pdev_release(struct device *dev)
+{
+}
+
+static struct platform_device the_pdev = {
+       /* should be the same name as driver_name */
+       .name = driver_name,
+       .id = -1,
+       .dev = {
+               .release = the_pdev_release,
+       },
+};
+
+static int __init vhci_hcd_init(void)
+{
+       int ret;
+
+       if (usb_disabled())
+               return -ENODEV;
+
+       ret = platform_driver_register(&vhci_driver);
+       if (ret)
+               goto err_driver_register;
+
+       ret = platform_device_register(&the_pdev);
+       if (ret)
+               goto err_platform_device_register;
+
+       pr_info(DRIVER_DESC " v" USBIP_VERSION "\n");
+       return ret;
+
+err_platform_device_register:
+       platform_driver_unregister(&vhci_driver);
+err_driver_register:
+       return ret;
+}
+
+static void __exit vhci_hcd_exit(void)
+{
+       platform_device_unregister(&the_pdev);
+       platform_driver_unregister(&vhci_driver);
+}
+
+module_init(vhci_hcd_init);
+module_exit(vhci_hcd_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_VERSION(USBIP_VERSION);
diff --git a/drivers/usb/usbip/vhci_rx.c b/drivers/usb/usbip/vhci_rx.c
new file mode 100644 (file)
index 0000000..00e4a54
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2003-2008 Takahiro Hirofuchi
+ *
+ * This 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 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/kthread.h>
+#include <linux/slab.h>
+
+#include "usbip_common.h"
+#include "vhci.h"
+
+/* get URB from transmitted urb queue. caller must hold vdev->priv_lock */
+struct urb *pickup_urb_and_free_priv(struct vhci_device *vdev, __u32 seqnum)
+{
+       struct vhci_priv *priv, *tmp;
+       struct urb *urb = NULL;
+       int status;
+
+       list_for_each_entry_safe(priv, tmp, &vdev->priv_rx, list) {
+               if (priv->seqnum != seqnum)
+                       continue;
+
+               urb = priv->urb;
+               status = urb->status;
+
+               usbip_dbg_vhci_rx("find urb %p vurb %p seqnum %u\n",
+                               urb, priv, seqnum);
+
+               switch (status) {
+               case -ENOENT:
+                       /* fall through */
+               case -ECONNRESET:
+                       dev_info(&urb->dev->dev,
+                                "urb %p was unlinked %ssynchronuously.\n", urb,
+                                status == -ENOENT ? "" : "a");
+                       break;
+               case -EINPROGRESS:
+                       /* no info output */
+                       break;
+               default:
+                       dev_info(&urb->dev->dev,
+                                "urb %p may be in a error, status %d\n", urb,
+                                status);
+               }
+
+               list_del(&priv->list);
+               kfree(priv);
+               urb->hcpriv = NULL;
+
+               break;
+       }
+
+       return urb;
+}
+
+static void vhci_recv_ret_submit(struct vhci_device *vdev,
+                                struct usbip_header *pdu)
+{
+       struct usbip_device *ud = &vdev->ud;
+       struct urb *urb;
+
+       spin_lock(&vdev->priv_lock);
+       urb = pickup_urb_and_free_priv(vdev, pdu->base.seqnum);
+       spin_unlock(&vdev->priv_lock);
+
+       if (!urb) {
+               pr_err("cannot find a urb of seqnum %u\n", pdu->base.seqnum);
+               pr_info("max seqnum %d\n",
+                       atomic_read(&the_controller->seqnum));
+               usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
+               return;
+       }
+
+       /* unpack the pdu to a urb */
+       usbip_pack_pdu(pdu, urb, USBIP_RET_SUBMIT, 0);
+
+       /* recv transfer buffer */
+       if (usbip_recv_xbuff(ud, urb) < 0)
+               return;
+
+       /* recv iso_packet_descriptor */
+       if (usbip_recv_iso(ud, urb) < 0)
+               return;
+
+       /* restore the padding in iso packets */
+       usbip_pad_iso(ud, urb);
+
+       if (usbip_dbg_flag_vhci_rx)
+               usbip_dump_urb(urb);
+
+       usbip_dbg_vhci_rx("now giveback urb %p\n", urb);
+
+       spin_lock(&the_controller->lock);
+       usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb);
+       spin_unlock(&the_controller->lock);
+
+       usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, urb->status);
+
+       usbip_dbg_vhci_rx("Leave\n");
+}
+
+static struct vhci_unlink *dequeue_pending_unlink(struct vhci_device *vdev,
+                                                 struct usbip_header *pdu)
+{
+       struct vhci_unlink *unlink, *tmp;
+
+       spin_lock(&vdev->priv_lock);
+
+       list_for_each_entry_safe(unlink, tmp, &vdev->unlink_rx, list) {
+               pr_info("unlink->seqnum %lu\n", unlink->seqnum);
+               if (unlink->seqnum == pdu->base.seqnum) {
+                       usbip_dbg_vhci_rx("found pending unlink, %lu\n",
+                                         unlink->seqnum);
+                       list_del(&unlink->list);
+
+                       spin_unlock(&vdev->priv_lock);
+                       return unlink;
+               }
+       }
+
+       spin_unlock(&vdev->priv_lock);
+
+       return NULL;
+}
+
+static void vhci_recv_ret_unlink(struct vhci_device *vdev,
+                                struct usbip_header *pdu)
+{
+       struct vhci_unlink *unlink;
+       struct urb *urb;
+
+       usbip_dump_header(pdu);
+
+       unlink = dequeue_pending_unlink(vdev, pdu);
+       if (!unlink) {
+               pr_info("cannot find the pending unlink %u\n",
+                       pdu->base.seqnum);
+               return;
+       }
+
+       spin_lock(&vdev->priv_lock);
+       urb = pickup_urb_and_free_priv(vdev, unlink->unlink_seqnum);
+       spin_unlock(&vdev->priv_lock);
+
+       if (!urb) {
+               /*
+                * I get the result of a unlink request. But, it seems that I
+                * already received the result of its submit result and gave
+                * back the URB.
+                */
+               pr_info("the urb (seqnum %d) was already given back\n",
+                       pdu->base.seqnum);
+       } else {
+               usbip_dbg_vhci_rx("now giveback urb %p\n", urb);
+
+               /* If unlink is successful, status is -ECONNRESET */
+               urb->status = pdu->u.ret_unlink.status;
+               pr_info("urb->status %d\n", urb->status);
+
+               spin_lock(&the_controller->lock);
+               usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb);
+               spin_unlock(&the_controller->lock);
+
+               usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb,
+                                    urb->status);
+       }
+
+       kfree(unlink);
+}
+
+static int vhci_priv_tx_empty(struct vhci_device *vdev)
+{
+       int empty = 0;
+
+       spin_lock(&vdev->priv_lock);
+       empty = list_empty(&vdev->priv_rx);
+       spin_unlock(&vdev->priv_lock);
+
+       return empty;
+}
+
+/* recv a pdu */
+static void vhci_rx_pdu(struct usbip_device *ud)
+{
+       int ret;
+       struct usbip_header pdu;
+       struct vhci_device *vdev = container_of(ud, struct vhci_device, ud);
+
+       usbip_dbg_vhci_rx("Enter\n");
+
+       memset(&pdu, 0, sizeof(pdu));
+
+       /* receive a pdu header */
+       ret = usbip_recv(ud->tcp_socket, &pdu, sizeof(pdu));
+       if (ret < 0) {
+               if (ret == -ECONNRESET)
+                       pr_info("connection reset by peer\n");
+               else if (ret == -EAGAIN) {
+                       /* ignore if connection was idle */
+                       if (vhci_priv_tx_empty(vdev))
+                               return;
+                       pr_info("connection timed out with pending urbs\n");
+               } else if (ret != -ERESTARTSYS)
+                       pr_info("xmit failed %d\n", ret);
+
+               usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
+               return;
+       }
+       if (ret == 0) {
+               pr_info("connection closed");
+               usbip_event_add(ud, VDEV_EVENT_DOWN);
+               return;
+       }
+       if (ret != sizeof(pdu)) {
+               pr_err("received pdu size is %d, should be %d\n", ret,
+                      (unsigned int)sizeof(pdu));
+               usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
+               return;
+       }
+
+       usbip_header_correct_endian(&pdu, 0);
+
+       if (usbip_dbg_flag_vhci_rx)
+               usbip_dump_header(&pdu);
+
+       switch (pdu.base.command) {
+       case USBIP_RET_SUBMIT:
+               vhci_recv_ret_submit(vdev, &pdu);
+               break;
+       case USBIP_RET_UNLINK:
+               vhci_recv_ret_unlink(vdev, &pdu);
+               break;
+       default:
+               /* NOT REACHED */
+               pr_err("unknown pdu %u\n", pdu.base.command);
+               usbip_dump_header(&pdu);
+               usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
+               break;
+       }
+}
+
+int vhci_rx_loop(void *data)
+{
+       struct usbip_device *ud = data;
+
+       while (!kthread_should_stop()) {
+               if (usbip_event_happened(ud))
+                       break;
+
+               vhci_rx_pdu(ud);
+       }
+
+       return 0;
+}
diff --git a/drivers/usb/usbip/vhci_sysfs.c b/drivers/usb/usbip/vhci_sysfs.c
new file mode 100644 (file)
index 0000000..211f43f
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2003-2008 Takahiro Hirofuchi
+ *
+ * This 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 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/kthread.h>
+#include <linux/file.h>
+#include <linux/net.h>
+
+#include "usbip_common.h"
+#include "vhci.h"
+
+/* TODO: refine locking ?*/
+
+/* Sysfs entry to show port status */
+static ssize_t status_show(struct device *dev, struct device_attribute *attr,
+                          char *out)
+{
+       char *s = out;
+       int i = 0;
+
+       BUG_ON(!the_controller || !out);
+
+       spin_lock(&the_controller->lock);
+
+       /*
+        * output example:
+        * prt sta spd dev socket           local_busid
+        * 000 004 000 000         c5a7bb80 1-2.3
+        * 001 004 000 000         d8cee980 2-3.4
+        *
+        * IP address can be retrieved from a socket pointer address by looking
+        * up /proc/net/{tcp,tcp6}. Also, a userland program may remember a
+        * port number and its peer IP address.
+        */
+       out += sprintf(out,
+                      "prt sta spd bus dev socket           local_busid\n");
+
+       for (i = 0; i < VHCI_NPORTS; i++) {
+               struct vhci_device *vdev = port_to_vdev(i);
+
+               spin_lock(&vdev->ud.lock);
+               out += sprintf(out, "%03u %03u ", i, vdev->ud.status);
+
+               if (vdev->ud.status == VDEV_ST_USED) {
+                       out += sprintf(out, "%03u %08x ",
+                                      vdev->speed, vdev->devid);
+                       out += sprintf(out, "%16p ", vdev->ud.tcp_socket);
+                       out += sprintf(out, "%s", dev_name(&vdev->udev->dev));
+
+               } else {
+                       out += sprintf(out, "000 000 000 0000000000000000 0-0");
+               }
+
+               out += sprintf(out, "\n");
+               spin_unlock(&vdev->ud.lock);
+       }
+
+       spin_unlock(&the_controller->lock);
+
+       return out - s;
+}
+static DEVICE_ATTR_RO(status);
+
+/* Sysfs entry to shutdown a virtual connection */
+static int vhci_port_disconnect(__u32 rhport)
+{
+       struct vhci_device *vdev;
+
+       usbip_dbg_vhci_sysfs("enter\n");
+
+       /* lock */
+       spin_lock(&the_controller->lock);
+
+       vdev = port_to_vdev(rhport);
+
+       spin_lock(&vdev->ud.lock);
+       if (vdev->ud.status == VDEV_ST_NULL) {
+               pr_err("not connected %d\n", vdev->ud.status);
+
+               /* unlock */
+               spin_unlock(&vdev->ud.lock);
+               spin_unlock(&the_controller->lock);
+
+               return -EINVAL;
+       }
+
+       /* unlock */
+       spin_unlock(&vdev->ud.lock);
+       spin_unlock(&the_controller->lock);
+
+       usbip_event_add(&vdev->ud, VDEV_EVENT_DOWN);
+
+       return 0;
+}
+
+static ssize_t store_detach(struct device *dev, struct device_attribute *attr,
+                           const char *buf, size_t count)
+{
+       int err;
+       __u32 rhport = 0;
+
+       if (sscanf(buf, "%u", &rhport) != 1)
+               return -EINVAL;
+
+       /* check rhport */
+       if (rhport >= VHCI_NPORTS) {
+               dev_err(dev, "invalid port %u\n", rhport);
+               return -EINVAL;
+       }
+
+       err = vhci_port_disconnect(rhport);
+       if (err < 0)
+               return -EINVAL;
+
+       usbip_dbg_vhci_sysfs("Leave\n");
+
+       return count;
+}
+static DEVICE_ATTR(detach, S_IWUSR, NULL, store_detach);
+
+/* Sysfs entry to establish a virtual connection */
+static int valid_args(__u32 rhport, enum usb_device_speed speed)
+{
+       /* check rhport */
+       if (rhport >= VHCI_NPORTS) {
+               pr_err("port %u\n", rhport);
+               return -EINVAL;
+       }
+
+       /* check speed */
+       switch (speed) {
+       case USB_SPEED_LOW:
+       case USB_SPEED_FULL:
+       case USB_SPEED_HIGH:
+       case USB_SPEED_WIRELESS:
+               break;
+       default:
+               pr_err("Failed attach request for unsupported USB speed: %s\n",
+                       usb_speed_string(speed));
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/*
+ * To start a new USB/IP attachment, a userland program needs to setup a TCP
+ * connection and then write its socket descriptor with remote device
+ * information into this sysfs file.
+ *
+ * A remote device is virtually attached to the root-hub port of @rhport with
+ * @speed. @devid is embedded into a request to specify the remote device in a
+ * server host.
+ *
+ * write() returns 0 on success, else negative errno.
+ */
+static ssize_t store_attach(struct device *dev, struct device_attribute *attr,
+                           const char *buf, size_t count)
+{
+       struct vhci_device *vdev;
+       struct socket *socket;
+       int sockfd = 0;
+       __u32 rhport = 0, devid = 0, speed = 0;
+       int err;
+
+       /*
+        * @rhport: port number of vhci_hcd
+        * @sockfd: socket descriptor of an established TCP connection
+        * @devid: unique device identifier in a remote host
+        * @speed: usb device speed in a remote host
+        */
+       if (sscanf(buf, "%u %u %u %u", &rhport, &sockfd, &devid, &speed) != 4)
+               return -EINVAL;
+
+       usbip_dbg_vhci_sysfs("rhport(%u) sockfd(%u) devid(%u) speed(%u)\n",
+                            rhport, sockfd, devid, speed);
+
+       /* check received parameters */
+       if (valid_args(rhport, speed) < 0)
+               return -EINVAL;
+
+       /* Extract socket from fd. */
+       socket = sockfd_lookup(sockfd, &err);
+       if (!socket)
+               return -EINVAL;
+
+       /* now need lock until setting vdev status as used */
+
+       /* begin a lock */
+       spin_lock(&the_controller->lock);
+       vdev = port_to_vdev(rhport);
+       spin_lock(&vdev->ud.lock);
+
+       if (vdev->ud.status != VDEV_ST_NULL) {
+               /* end of the lock */
+               spin_unlock(&vdev->ud.lock);
+               spin_unlock(&the_controller->lock);
+
+               sockfd_put(socket);
+
+               dev_err(dev, "port %d already used\n", rhport);
+               return -EINVAL;
+       }
+
+       dev_info(dev,
+                "rhport(%u) sockfd(%d) devid(%u) speed(%u) speed_str(%s)\n",
+                rhport, sockfd, devid, speed, usb_speed_string(speed));
+
+       vdev->devid         = devid;
+       vdev->speed         = speed;
+       vdev->ud.tcp_socket = socket;
+       vdev->ud.status     = VDEV_ST_NOTASSIGNED;
+
+       spin_unlock(&vdev->ud.lock);
+       spin_unlock(&the_controller->lock);
+       /* end the lock */
+
+       vdev->ud.tcp_rx = kthread_get_run(vhci_rx_loop, &vdev->ud, "vhci_rx");
+       vdev->ud.tcp_tx = kthread_get_run(vhci_tx_loop, &vdev->ud, "vhci_tx");
+
+       rh_port_connect(rhport, speed);
+
+       return count;
+}
+static DEVICE_ATTR(attach, S_IWUSR, NULL, store_attach);
+
+static struct attribute *dev_attrs[] = {
+       &dev_attr_status.attr,
+       &dev_attr_detach.attr,
+       &dev_attr_attach.attr,
+       &dev_attr_usbip_debug.attr,
+       NULL,
+};
+
+const struct attribute_group dev_attr_group = {
+       .attrs = dev_attrs,
+};
diff --git a/drivers/usb/usbip/vhci_tx.c b/drivers/usb/usbip/vhci_tx.c
new file mode 100644 (file)
index 0000000..409fd99
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2003-2008 Takahiro Hirofuchi
+ *
+ * This 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 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/kthread.h>
+#include <linux/slab.h>
+
+#include "usbip_common.h"
+#include "vhci.h"
+
+static void setup_cmd_submit_pdu(struct usbip_header *pdup,  struct urb *urb)
+{
+       struct vhci_priv *priv = ((struct vhci_priv *)urb->hcpriv);
+       struct vhci_device *vdev = priv->vdev;
+
+       usbip_dbg_vhci_tx("URB, local devnum %u, remote devid %u\n",
+                         usb_pipedevice(urb->pipe), vdev->devid);
+
+       pdup->base.command   = USBIP_CMD_SUBMIT;
+       pdup->base.seqnum    = priv->seqnum;
+       pdup->base.devid     = vdev->devid;
+       pdup->base.direction = usb_pipein(urb->pipe) ?
+               USBIP_DIR_IN : USBIP_DIR_OUT;
+       pdup->base.ep        = usb_pipeendpoint(urb->pipe);
+
+       usbip_pack_pdu(pdup, urb, USBIP_CMD_SUBMIT, 1);
+
+       if (urb->setup_packet)
+               memcpy(pdup->u.cmd_submit.setup, urb->setup_packet, 8);
+}
+
+static struct vhci_priv *dequeue_from_priv_tx(struct vhci_device *vdev)
+{
+       struct vhci_priv *priv, *tmp;
+
+       spin_lock(&vdev->priv_lock);
+
+       list_for_each_entry_safe(priv, tmp, &vdev->priv_tx, list) {
+               list_move_tail(&priv->list, &vdev->priv_rx);
+               spin_unlock(&vdev->priv_lock);
+               return priv;
+       }
+
+       spin_unlock(&vdev->priv_lock);
+
+       return NULL;
+}
+
+static int vhci_send_cmd_submit(struct vhci_device *vdev)
+{
+       struct vhci_priv *priv = NULL;
+
+       struct msghdr msg;
+       struct kvec iov[3];
+       size_t txsize;
+
+       size_t total_size = 0;
+
+       while ((priv = dequeue_from_priv_tx(vdev)) != NULL) {
+               int ret;
+               struct urb *urb = priv->urb;
+               struct usbip_header pdu_header;
+               struct usbip_iso_packet_descriptor *iso_buffer = NULL;
+
+               txsize = 0;
+               memset(&pdu_header, 0, sizeof(pdu_header));
+               memset(&msg, 0, sizeof(msg));
+               memset(&iov, 0, sizeof(iov));
+
+               usbip_dbg_vhci_tx("setup txdata urb %p\n", urb);
+
+               /* 1. setup usbip_header */
+               setup_cmd_submit_pdu(&pdu_header, urb);
+               usbip_header_correct_endian(&pdu_header, 1);
+
+               iov[0].iov_base = &pdu_header;
+               iov[0].iov_len  = sizeof(pdu_header);
+               txsize += sizeof(pdu_header);
+
+               /* 2. setup transfer buffer */
+               if (!usb_pipein(urb->pipe) && urb->transfer_buffer_length > 0) {
+                       iov[1].iov_base = urb->transfer_buffer;
+                       iov[1].iov_len  = urb->transfer_buffer_length;
+                       txsize += urb->transfer_buffer_length;
+               }
+
+               /* 3. setup iso_packet_descriptor */
+               if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+                       ssize_t len = 0;
+
+                       iso_buffer = usbip_alloc_iso_desc_pdu(urb, &len);
+                       if (!iso_buffer) {
+                               usbip_event_add(&vdev->ud,
+                                               SDEV_EVENT_ERROR_MALLOC);
+                               return -1;
+                       }
+
+                       iov[2].iov_base = iso_buffer;
+                       iov[2].iov_len  = len;
+                       txsize += len;
+               }
+
+               ret = kernel_sendmsg(vdev->ud.tcp_socket, &msg, iov, 3, txsize);
+               if (ret != txsize) {
+                       pr_err("sendmsg failed!, ret=%d for %zd\n", ret,
+                              txsize);
+                       kfree(iso_buffer);
+                       usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_TCP);
+                       return -1;
+               }
+
+               kfree(iso_buffer);
+               usbip_dbg_vhci_tx("send txdata\n");
+
+               total_size += txsize;
+       }
+
+       return total_size;
+}
+
+static struct vhci_unlink *dequeue_from_unlink_tx(struct vhci_device *vdev)
+{
+       struct vhci_unlink *unlink, *tmp;
+
+       spin_lock(&vdev->priv_lock);
+
+       list_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) {
+               list_move_tail(&unlink->list, &vdev->unlink_rx);
+               spin_unlock(&vdev->priv_lock);
+               return unlink;
+       }
+
+       spin_unlock(&vdev->priv_lock);
+
+       return NULL;
+}
+
+static int vhci_send_cmd_unlink(struct vhci_device *vdev)
+{
+       struct vhci_unlink *unlink = NULL;
+
+       struct msghdr msg;
+       struct kvec iov[3];
+       size_t txsize;
+
+       size_t total_size = 0;
+
+       while ((unlink = dequeue_from_unlink_tx(vdev)) != NULL) {
+               int ret;
+               struct usbip_header pdu_header;
+
+               txsize = 0;
+               memset(&pdu_header, 0, sizeof(pdu_header));
+               memset(&msg, 0, sizeof(msg));
+               memset(&iov, 0, sizeof(iov));
+
+               usbip_dbg_vhci_tx("setup cmd unlink, %lu\n", unlink->seqnum);
+
+               /* 1. setup usbip_header */
+               pdu_header.base.command = USBIP_CMD_UNLINK;
+               pdu_header.base.seqnum  = unlink->seqnum;
+               pdu_header.base.devid   = vdev->devid;
+               pdu_header.base.ep      = 0;
+               pdu_header.u.cmd_unlink.seqnum = unlink->unlink_seqnum;
+
+               usbip_header_correct_endian(&pdu_header, 1);
+
+               iov[0].iov_base = &pdu_header;
+               iov[0].iov_len  = sizeof(pdu_header);
+               txsize += sizeof(pdu_header);
+
+               ret = kernel_sendmsg(vdev->ud.tcp_socket, &msg, iov, 1, txsize);
+               if (ret != txsize) {
+                       pr_err("sendmsg failed!, ret=%d for %zd\n", ret,
+                              txsize);
+                       usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_TCP);
+                       return -1;
+               }
+
+               usbip_dbg_vhci_tx("send txdata\n");
+
+               total_size += txsize;
+       }
+
+       return total_size;
+}
+
+int vhci_tx_loop(void *data)
+{
+       struct usbip_device *ud = data;
+       struct vhci_device *vdev = container_of(ud, struct vhci_device, ud);
+
+       while (!kthread_should_stop()) {
+               if (vhci_send_cmd_submit(vdev) < 0)
+                       break;
+
+               if (vhci_send_cmd_unlink(vdev) < 0)
+                       break;
+
+               wait_event_interruptible(vdev->waitq_tx,
+                                        (!list_empty(&vdev->priv_tx) ||
+                                         !list_empty(&vdev->unlink_tx) ||
+                                         kthread_should_stop()));
+
+               usbip_dbg_vhci_tx("pending urbs ?, now wake up\n");
+       }
+
+       return 0;
+}
index 3e2e4ed2015739bf9acd3cea2a7fd22fa8c3a1d8..e279015be466166742367f7bcb958639f856b447 100644 (file)
@@ -2602,6 +2602,7 @@ static void wa_buf_in_cb(struct urb *urb)
        dev = &wa->usb_iface->dev;
        --(wa->active_buf_in_urbs);
        active_buf_in_urbs = wa->active_buf_in_urbs;
+       rpipe = xfer->ep->hcpriv;
 
        if (usb_pipeisoc(xfer->urb->pipe)) {
                struct usb_iso_packet_descriptor *iso_frame_desc =
@@ -2659,7 +2660,6 @@ static void wa_buf_in_cb(struct urb *urb)
                          resubmit_dti = (isoc_data_frame_count ==
                                                        urb_frame_count);
                } else if (active_buf_in_urbs == 0) {
-                       rpipe = xfer->ep->hcpriv;
                        dev_dbg(dev,
                                "xfer %p 0x%08X#%u: data in done (%zu bytes)\n",
                                xfer, wa_xfer_id(xfer), seg->index,
@@ -2685,7 +2685,6 @@ static void wa_buf_in_cb(struct urb *urb)
                 */
                resubmit_dti = wa->dti_state != WA_DTI_TRANSFER_RESULT_PENDING;
                spin_lock_irqsave(&xfer->lock, flags);
-               rpipe = xfer->ep->hcpriv;
                if (printk_ratelimit())
                        dev_err(dev, "xfer %p 0x%08X#%u: data in error %d\n",
                                xfer, wa_xfer_id(xfer), seg->index,
index d7a3d13e72ec3900232c34ab35d121eadfff2683..b85983e97f0afbc70665d1aa134d5b182e25976e 100644 (file)
@@ -173,6 +173,7 @@ static int pwm_backlight_parse_dt(struct device *dev,
                data->max_brightness--;
        }
 
+       data->enable_gpio = -EINVAL;
        return 0;
 }
 
index beadd3edaa176625aaeb47440a44b830e5c78fd4..a7b6217ac87b4086eae386ed6ebaafe9cf500481 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/list.h>
 #include <linux/amba/bus.h>
 #include <linux/amba/clcd.h>
+#include <linux/bitops.h>
 #include <linux/clk.h>
 #include <linux/hardirq.h>
 #include <linux/dma-mapping.h>
@@ -650,6 +651,7 @@ static int clcdfb_of_init_display(struct clcd_fb *fb)
 {
        struct device_node *endpoint;
        int err;
+       unsigned int bpp;
        u32 max_bandwidth;
        u32 tft_r0b0g0[3];
 
@@ -667,11 +669,22 @@ static int clcdfb_of_init_display(struct clcd_fb *fb)
 
        err = of_property_read_u32(fb->dev->dev.of_node, "max-memory-bandwidth",
                        &max_bandwidth);
-       if (!err)
-               fb->panel->bpp = 8 * max_bandwidth / (fb->panel->mode.xres *
-                               fb->panel->mode.yres * fb->panel->mode.refresh);
-       else
-               fb->panel->bpp = 32;
+       if (!err) {
+               /*
+                * max_bandwidth is in bytes per second and pixclock in
+                * pico-seconds, so the maximum allowed bits per pixel is
+                *   8 * max_bandwidth / (PICOS2KHZ(pixclock) * 1000)
+                * Rearrange this calculation to avoid overflow and then ensure
+                * result is a valid format.
+                */
+               bpp = max_bandwidth / (1000 / 8)
+                       / PICOS2KHZ(fb->panel->mode.pixclock);
+               bpp = rounddown_pow_of_two(bpp);
+               if (bpp > 32)
+                       bpp = 32;
+       } else
+               bpp = 32;
+       fb->panel->bpp = bpp;
 
 #ifdef CONFIG_CPU_BIG_ENDIAN
        fb->panel->cntl |= CNTL_BEBO;
index 92640d46770a19f5b249f63ad4b020fa6fa84b1a..1d8bdb92939b2c034dbd6b7e15f3b076146a6c6a 100644 (file)
@@ -1102,12 +1102,14 @@ static int atmel_lcdfb_of_init(struct atmel_lcdfb_info *sinfo)
        timings = of_get_display_timings(display_np);
        if (!timings) {
                dev_err(dev, "failed to get display timings\n");
+               ret = -EINVAL;
                goto put_display_node;
        }
 
        timings_np = of_find_node_by_name(display_np, "display-timings");
        if (!timings_np) {
                dev_err(dev, "failed to find display-timings node\n");
+               ret = -ENODEV;
                goto put_display_node;
        }
 
index 206a66b61072f5d1bd97c6d21453b0a9e6f99f18..59abdc6a97f668ed1b67e6bd9e958b74479bd99e 100644 (file)
@@ -273,7 +273,7 @@ static struct chips_init_reg chips_init_xr[] = {
        { 0xa8, 0x00 }
 };
 
-static void __init chips_hw_init(void)
+static void chips_hw_init(void)
 {
        int i;
 
index 788f6b37fce703aec7ef08b91abd9c77d3fdd4e7..10c876c95772350cdb890e001b7ea4b3cd838358 100644 (file)
@@ -419,7 +419,7 @@ static void lcd_cfg_horizontal_sync(int back_porch, int pulse_width,
 {
        u32 reg;
 
-       reg = lcdc_read(LCD_RASTER_TIMING_0_REG) & 0xf;
+       reg = lcdc_read(LCD_RASTER_TIMING_0_REG) & 0x3ff;
        reg |= (((back_porch-1) & 0xff) << 24)
            | (((front_porch-1) & 0xff) << 16)
            | (((pulse_width-1) & 0x3f) << 10);
index 987edf1100380b9d075067c659980931cfbda31b..5c098d5b40432ef2cec004ce420ef9660ef81599 100644 (file)
@@ -236,6 +236,7 @@ timingfail:
        if (native_mode)
                of_node_put(native_mode);
        display_timings_release(disp);
+       disp = NULL;
 entryfail:
        kfree(disp);
 dispfail:
index bd7ec2cc2674d73ab71405769ce53b922a0c0082..733750096b71b38d23783926b4f85da9ac2d35ea 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -141,6 +141,7 @@ struct kioctx {
 
        struct {
                unsigned        tail;
+               unsigned        completed_events;
                spinlock_t      completion_lock;
        } ____cacheline_aligned_in_smp;
 
@@ -192,7 +193,6 @@ static struct file *aio_private_file(struct kioctx *ctx, loff_t nr_pages)
        }
 
        file->f_flags = O_RDWR;
-       file->private_data = ctx;
        return file;
 }
 
@@ -202,7 +202,7 @@ static struct dentry *aio_mount(struct file_system_type *fs_type,
        static const struct dentry_operations ops = {
                .d_dname        = simple_dname,
        };
-       return mount_pseudo(fs_type, "aio:", NULL, &ops, 0xa10a10a1);
+       return mount_pseudo(fs_type, "aio:", NULL, &ops, AIO_RING_MAGIC);
 }
 
 /* aio_setup
@@ -556,8 +556,7 @@ static int ioctx_add_table(struct kioctx *ctx, struct mm_struct *mm)
        struct aio_ring *ring;
 
        spin_lock(&mm->ioctx_lock);
-       rcu_read_lock();
-       table = rcu_dereference(mm->ioctx_table);
+       table = rcu_dereference_raw(mm->ioctx_table);
 
        while (1) {
                if (table)
@@ -565,7 +564,6 @@ static int ioctx_add_table(struct kioctx *ctx, struct mm_struct *mm)
                                if (!table->table[i]) {
                                        ctx->id = i;
                                        table->table[i] = ctx;
-                                       rcu_read_unlock();
                                        spin_unlock(&mm->ioctx_lock);
 
                                        /* While kioctx setup is in progress,
@@ -579,8 +577,6 @@ static int ioctx_add_table(struct kioctx *ctx, struct mm_struct *mm)
                                }
 
                new_nr = (table ? table->nr : 1) * 4;
-
-               rcu_read_unlock();
                spin_unlock(&mm->ioctx_lock);
 
                table = kzalloc(sizeof(*table) + sizeof(struct kioctx *) *
@@ -591,8 +587,7 @@ static int ioctx_add_table(struct kioctx *ctx, struct mm_struct *mm)
                table->nr = new_nr;
 
                spin_lock(&mm->ioctx_lock);
-               rcu_read_lock();
-               old = rcu_dereference(mm->ioctx_table);
+               old = rcu_dereference_raw(mm->ioctx_table);
 
                if (!old) {
                        rcu_assign_pointer(mm->ioctx_table, table);
@@ -739,12 +734,9 @@ static int kill_ioctx(struct mm_struct *mm, struct kioctx *ctx,
 
 
        spin_lock(&mm->ioctx_lock);
-       rcu_read_lock();
-       table = rcu_dereference(mm->ioctx_table);
-
+       table = rcu_dereference_raw(mm->ioctx_table);
        WARN_ON(ctx != table->table[ctx->id]);
        table->table[ctx->id] = NULL;
-       rcu_read_unlock();
        spin_unlock(&mm->ioctx_lock);
 
        /* percpu_ref_kill() will do the necessary call_rcu() */
@@ -793,40 +785,35 @@ EXPORT_SYMBOL(wait_on_sync_kiocb);
  */
 void exit_aio(struct mm_struct *mm)
 {
-       struct kioctx_table *table;
-       struct kioctx *ctx;
-       unsigned i = 0;
-
-       while (1) {
-               rcu_read_lock();
-               table = rcu_dereference(mm->ioctx_table);
-
-               do {
-                       if (!table || i >= table->nr) {
-                               rcu_read_unlock();
-                               rcu_assign_pointer(mm->ioctx_table, NULL);
-                               if (table)
-                                       kfree(table);
-                               return;
-                       }
+       struct kioctx_table *table = rcu_dereference_raw(mm->ioctx_table);
+       int i;
 
-                       ctx = table->table[i++];
-               } while (!ctx);
+       if (!table)
+               return;
 
-               rcu_read_unlock();
+       for (i = 0; i < table->nr; ++i) {
+               struct kioctx *ctx = table->table[i];
+               struct completion requests_done =
+                       COMPLETION_INITIALIZER_ONSTACK(requests_done);
 
+               if (!ctx)
+                       continue;
                /*
-                * We don't need to bother with munmap() here -
-                * exit_mmap(mm) is coming and it'll unmap everything.
-                * Since aio_free_ring() uses non-zero ->mmap_size
-                * as indicator that it needs to unmap the area,
-                * just set it to 0; aio_free_ring() is the only
-                * place that uses ->mmap_size, so it's safe.
+                * We don't need to bother with munmap() here - exit_mmap(mm)
+                * is coming and it'll unmap everything. And we simply can't,
+                * this is not necessarily our ->mm.
+                * Since kill_ioctx() uses non-zero ->mmap_size as indicator
+                * that it needs to unmap the area, just set it to 0.
                 */
                ctx->mmap_size = 0;
+               kill_ioctx(mm, ctx, &requests_done);
 
-               kill_ioctx(mm, ctx, NULL);
+               /* Wait until all IO for the context are done. */
+               wait_for_completion(&requests_done);
        }
+
+       RCU_INIT_POINTER(mm->ioctx_table, NULL);
+       kfree(table);
 }
 
 static void put_reqs_available(struct kioctx *ctx, unsigned nr)
@@ -834,10 +821,8 @@ static void put_reqs_available(struct kioctx *ctx, unsigned nr)
        struct kioctx_cpu *kcpu;
        unsigned long flags;
 
-       preempt_disable();
-       kcpu = this_cpu_ptr(ctx->cpu);
-
        local_irq_save(flags);
+       kcpu = this_cpu_ptr(ctx->cpu);
        kcpu->reqs_available += nr;
 
        while (kcpu->reqs_available >= ctx->req_batch * 2) {
@@ -846,7 +831,6 @@ static void put_reqs_available(struct kioctx *ctx, unsigned nr)
        }
 
        local_irq_restore(flags);
-       preempt_enable();
 }
 
 static bool get_reqs_available(struct kioctx *ctx)
@@ -855,10 +839,8 @@ static bool get_reqs_available(struct kioctx *ctx)
        bool ret = false;
        unsigned long flags;
 
-       preempt_disable();
-       kcpu = this_cpu_ptr(ctx->cpu);
-
        local_irq_save(flags);
+       kcpu = this_cpu_ptr(ctx->cpu);
        if (!kcpu->reqs_available) {
                int old, avail = atomic_read(&ctx->reqs_available);
 
@@ -878,10 +860,71 @@ static bool get_reqs_available(struct kioctx *ctx)
        kcpu->reqs_available--;
 out:
        local_irq_restore(flags);
-       preempt_enable();
        return ret;
 }
 
+/* refill_reqs_available
+ *     Updates the reqs_available reference counts used for tracking the
+ *     number of free slots in the completion ring.  This can be called
+ *     from aio_complete() (to optimistically update reqs_available) or
+ *     from aio_get_req() (the we're out of events case).  It must be
+ *     called holding ctx->completion_lock.
+ */
+static void refill_reqs_available(struct kioctx *ctx, unsigned head,
+                                  unsigned tail)
+{
+       unsigned events_in_ring, completed;
+
+       /* Clamp head since userland can write to it. */
+       head %= ctx->nr_events;
+       if (head <= tail)
+               events_in_ring = tail - head;
+       else
+               events_in_ring = ctx->nr_events - (head - tail);
+
+       completed = ctx->completed_events;
+       if (events_in_ring < completed)
+               completed -= events_in_ring;
+       else
+               completed = 0;
+
+       if (!completed)
+               return;
+
+       ctx->completed_events -= completed;
+       put_reqs_available(ctx, completed);
+}
+
+/* user_refill_reqs_available
+ *     Called to refill reqs_available when aio_get_req() encounters an
+ *     out of space in the completion ring.
+ */
+static void user_refill_reqs_available(struct kioctx *ctx)
+{
+       spin_lock_irq(&ctx->completion_lock);
+       if (ctx->completed_events) {
+               struct aio_ring *ring;
+               unsigned head;
+
+               /* Access of ring->head may race with aio_read_events_ring()
+                * here, but that's okay since whether we read the old version
+                * or the new version, and either will be valid.  The important
+                * part is that head cannot pass tail since we prevent
+                * aio_complete() from updating tail by holding
+                * ctx->completion_lock.  Even if head is invalid, the check
+                * against ctx->completed_events below will make sure we do the
+                * safe/right thing.
+                */
+               ring = kmap_atomic(ctx->ring_pages[0]);
+               head = ring->head;
+               kunmap_atomic(ring);
+
+               refill_reqs_available(ctx, head, ctx->tail);
+       }
+
+       spin_unlock_irq(&ctx->completion_lock);
+}
+
 /* aio_get_req
  *     Allocate a slot for an aio request.
  * Returns NULL if no requests are free.
@@ -890,8 +933,11 @@ static inline struct kiocb *aio_get_req(struct kioctx *ctx)
 {
        struct kiocb *req;
 
-       if (!get_reqs_available(ctx))
-               return NULL;
+       if (!get_reqs_available(ctx)) {
+               user_refill_reqs_available(ctx);
+               if (!get_reqs_available(ctx))
+                       return NULL;
+       }
 
        req = kmem_cache_alloc(kiocb_cachep, GFP_KERNEL|__GFP_ZERO);
        if (unlikely(!req))
@@ -950,8 +996,8 @@ void aio_complete(struct kiocb *iocb, long res, long res2)
        struct kioctx   *ctx = iocb->ki_ctx;
        struct aio_ring *ring;
        struct io_event *ev_page, *event;
+       unsigned tail, pos, head;
        unsigned long   flags;
-       unsigned tail, pos;
 
        /*
         * Special case handling for sync iocbs:
@@ -1012,10 +1058,14 @@ void aio_complete(struct kiocb *iocb, long res, long res2)
        ctx->tail = tail;
 
        ring = kmap_atomic(ctx->ring_pages[0]);
+       head = ring->head;
        ring->tail = tail;
        kunmap_atomic(ring);
        flush_dcache_page(ctx->ring_pages[0]);
 
+       ctx->completed_events++;
+       if (ctx->completed_events > 1)
+               refill_reqs_available(ctx, head, tail);
        spin_unlock_irqrestore(&ctx->completion_lock, flags);
 
        pr_debug("added to ring %p at [%u]\n", iocb, tail);
@@ -1030,7 +1080,6 @@ void aio_complete(struct kiocb *iocb, long res, long res2)
 
        /* everything turned out well, dispose of the aiocb. */
        kiocb_free(iocb);
-       put_reqs_available(ctx, 1);
 
        /*
         * We have to order our ring_info tail store above and test
@@ -1047,7 +1096,7 @@ void aio_complete(struct kiocb *iocb, long res, long res2)
 }
 EXPORT_SYMBOL(aio_complete);
 
-/* aio_read_events
+/* aio_read_events_ring
  *     Pull an event off of the ioctx's event ring.  Returns the number of
  *     events fetched
  */
@@ -1067,6 +1116,12 @@ static long aio_read_events_ring(struct kioctx *ctx,
        tail = ring->tail;
        kunmap_atomic(ring);
 
+       /*
+        * Ensure that once we've read the current tail pointer, that
+        * we also see the events that were stored up to the tail.
+        */
+       smp_rmb();
+
        pr_debug("h%u t%u m%u\n", head, tail, ctx->nr_events);
 
        if (head == tail)
@@ -1270,12 +1325,12 @@ static ssize_t aio_setup_vectored_rw(struct kiocb *kiocb,
        if (compat)
                ret = compat_rw_copy_check_uvector(rw,
                                (struct compat_iovec __user *)buf,
-                               *nr_segs, 1, *iovec, iovec);
+                               *nr_segs, UIO_FASTIOV, *iovec, iovec);
        else
 #endif
                ret = rw_copy_check_uvector(rw,
                                (struct iovec __user *)buf,
-                               *nr_segs, 1, *iovec, iovec);
+                               *nr_segs, UIO_FASTIOV, *iovec, iovec);
        if (ret < 0)
                return ret;
 
@@ -1299,9 +1354,8 @@ static ssize_t aio_setup_single_vector(struct kiocb *kiocb,
 }
 
 /*
- * aio_setup_iocb:
- *     Performs the initial checks and aio retry method
- *     setup for the kiocb at the time of io submission.
+ * aio_run_iocb:
+ *     Performs the initial checks and io submission.
  */
 static ssize_t aio_run_iocb(struct kiocb *req, unsigned opcode,
                            char __user *buf, bool compat)
@@ -1313,7 +1367,7 @@ static ssize_t aio_run_iocb(struct kiocb *req, unsigned opcode,
        fmode_t mode;
        aio_rw_op *rw_op;
        rw_iter_op *iter_op;
-       struct iovec inline_vec, *iovec = &inline_vec;
+       struct iovec inline_vecs[UIO_FASTIOV], *iovec = inline_vecs;
        struct iov_iter iter;
 
        switch (opcode) {
@@ -1348,7 +1402,7 @@ rw_common:
                if (!ret)
                        ret = rw_verify_area(rw, file, &req->ki_pos, req->ki_nbytes);
                if (ret < 0) {
-                       if (iovec != &inline_vec)
+                       if (iovec != inline_vecs)
                                kfree(iovec);
                        return ret;
                }
@@ -1395,7 +1449,7 @@ rw_common:
                return -EINVAL;
        }
 
-       if (iovec != &inline_vec)
+       if (iovec != inline_vecs)
                kfree(iovec);
 
        if (ret != -EIOCBQUEUED) {
index 5a201d81049c09fcb280f26539d0ad5c6c5c5b51..fbd76ded9a34b3260a5e794115fff0312b3c6e08 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/list.h>
 #include <linux/spinlock.h>
 #include <linux/freezer.h>
-#include <linux/workqueue.h>
 #include "async-thread.h"
 #include "ctree.h"
 
@@ -55,8 +54,39 @@ struct btrfs_workqueue {
        struct __btrfs_workqueue *high;
 };
 
-static inline struct __btrfs_workqueue
-*__btrfs_alloc_workqueue(const char *name, int flags, int max_active,
+static void normal_work_helper(struct btrfs_work *work);
+
+#define BTRFS_WORK_HELPER(name)                                        \
+void btrfs_##name(struct work_struct *arg)                             \
+{                                                                      \
+       struct btrfs_work *work = container_of(arg, struct btrfs_work,  \
+                                              normal_work);            \
+       normal_work_helper(work);                                       \
+}
+
+BTRFS_WORK_HELPER(worker_helper);
+BTRFS_WORK_HELPER(delalloc_helper);
+BTRFS_WORK_HELPER(flush_delalloc_helper);
+BTRFS_WORK_HELPER(cache_helper);
+BTRFS_WORK_HELPER(submit_helper);
+BTRFS_WORK_HELPER(fixup_helper);
+BTRFS_WORK_HELPER(endio_helper);
+BTRFS_WORK_HELPER(endio_meta_helper);
+BTRFS_WORK_HELPER(endio_meta_write_helper);
+BTRFS_WORK_HELPER(endio_raid56_helper);
+BTRFS_WORK_HELPER(rmw_helper);
+BTRFS_WORK_HELPER(endio_write_helper);
+BTRFS_WORK_HELPER(freespace_write_helper);
+BTRFS_WORK_HELPER(delayed_meta_helper);
+BTRFS_WORK_HELPER(readahead_helper);
+BTRFS_WORK_HELPER(qgroup_rescan_helper);
+BTRFS_WORK_HELPER(extent_refs_helper);
+BTRFS_WORK_HELPER(scrub_helper);
+BTRFS_WORK_HELPER(scrubwrc_helper);
+BTRFS_WORK_HELPER(scrubnc_helper);
+
+static struct __btrfs_workqueue *
+__btrfs_alloc_workqueue(const char *name, int flags, int max_active,
                         int thresh)
 {
        struct __btrfs_workqueue *ret = kzalloc(sizeof(*ret), GFP_NOFS);
@@ -232,13 +262,11 @@ static void run_ordered_work(struct __btrfs_workqueue *wq)
        spin_unlock_irqrestore(lock, flags);
 }
 
-static void normal_work_helper(struct work_struct *arg)
+static void normal_work_helper(struct btrfs_work *work)
 {
-       struct btrfs_work *work;
        struct __btrfs_workqueue *wq;
        int need_order = 0;
 
-       work = container_of(arg, struct btrfs_work, normal_work);
        /*
         * We should not touch things inside work in the following cases:
         * 1) after work->func() if it has no ordered_free
@@ -262,7 +290,7 @@ static void normal_work_helper(struct work_struct *arg)
                trace_btrfs_all_work_done(work);
 }
 
-void btrfs_init_work(struct btrfs_work *work,
+void btrfs_init_work(struct btrfs_work *work, btrfs_work_func_t uniq_func,
                     btrfs_func_t func,
                     btrfs_func_t ordered_func,
                     btrfs_func_t ordered_free)
@@ -270,7 +298,7 @@ void btrfs_init_work(struct btrfs_work *work,
        work->func = func;
        work->ordered_func = ordered_func;
        work->ordered_free = ordered_free;
-       INIT_WORK(&work->normal_work, normal_work_helper);
+       INIT_WORK(&work->normal_work, uniq_func);
        INIT_LIST_HEAD(&work->ordered_list);
        work->flags = 0;
 }
index 9c6b66d15fb0a07cd0a6a4656d6865848aa5c8ea..e9e31c94758fd6ddea5cbd458d5aca04a27e9a73 100644 (file)
 
 #ifndef __BTRFS_ASYNC_THREAD_
 #define __BTRFS_ASYNC_THREAD_
+#include <linux/workqueue.h>
 
 struct btrfs_workqueue;
 /* Internal use only */
 struct __btrfs_workqueue;
 struct btrfs_work;
 typedef void (*btrfs_func_t)(struct btrfs_work *arg);
+typedef void (*btrfs_work_func_t)(struct work_struct *arg);
 
 struct btrfs_work {
        btrfs_func_t func;
@@ -38,11 +40,35 @@ struct btrfs_work {
        unsigned long flags;
 };
 
+#define BTRFS_WORK_HELPER_PROTO(name)                                  \
+void btrfs_##name(struct work_struct *arg)
+
+BTRFS_WORK_HELPER_PROTO(worker_helper);
+BTRFS_WORK_HELPER_PROTO(delalloc_helper);
+BTRFS_WORK_HELPER_PROTO(flush_delalloc_helper);
+BTRFS_WORK_HELPER_PROTO(cache_helper);
+BTRFS_WORK_HELPER_PROTO(submit_helper);
+BTRFS_WORK_HELPER_PROTO(fixup_helper);
+BTRFS_WORK_HELPER_PROTO(endio_helper);
+BTRFS_WORK_HELPER_PROTO(endio_meta_helper);
+BTRFS_WORK_HELPER_PROTO(endio_meta_write_helper);
+BTRFS_WORK_HELPER_PROTO(endio_raid56_helper);
+BTRFS_WORK_HELPER_PROTO(rmw_helper);
+BTRFS_WORK_HELPER_PROTO(endio_write_helper);
+BTRFS_WORK_HELPER_PROTO(freespace_write_helper);
+BTRFS_WORK_HELPER_PROTO(delayed_meta_helper);
+BTRFS_WORK_HELPER_PROTO(readahead_helper);
+BTRFS_WORK_HELPER_PROTO(qgroup_rescan_helper);
+BTRFS_WORK_HELPER_PROTO(extent_refs_helper);
+BTRFS_WORK_HELPER_PROTO(scrub_helper);
+BTRFS_WORK_HELPER_PROTO(scrubwrc_helper);
+BTRFS_WORK_HELPER_PROTO(scrubnc_helper);
+
 struct btrfs_workqueue *btrfs_alloc_workqueue(const char *name,
                                              int flags,
                                              int max_active,
                                              int thresh);
-void btrfs_init_work(struct btrfs_work *work,
+void btrfs_init_work(struct btrfs_work *work, btrfs_work_func_t helper,
                     btrfs_func_t func,
                     btrfs_func_t ordered_func,
                     btrfs_func_t ordered_free);
index e25564bfcb463383e94eba0ce7f2f3769898afe7..54a201dac7f9455bd1e294c2731d5b47226b7bef 100644 (file)
@@ -276,9 +276,8 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
                        }
                        if (ret > 0)
                                goto next;
-                       ret = ulist_add_merge(parents, eb->start,
-                                             (uintptr_t)eie,
-                                             (u64 *)&old, GFP_NOFS);
+                       ret = ulist_add_merge_ptr(parents, eb->start,
+                                                 eie, (void **)&old, GFP_NOFS);
                        if (ret < 0)
                                break;
                        if (!ret && extent_item_pos) {
@@ -1001,16 +1000,19 @@ again:
                                        ret = -EIO;
                                        goto out;
                                }
+                               btrfs_tree_read_lock(eb);
+                               btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK);
                                ret = find_extent_in_eb(eb, bytenr,
                                                        *extent_item_pos, &eie);
+                               btrfs_tree_read_unlock_blocking(eb);
                                free_extent_buffer(eb);
                                if (ret < 0)
                                        goto out;
                                ref->inode_list = eie;
                        }
-                       ret = ulist_add_merge(refs, ref->parent,
-                                             (uintptr_t)ref->inode_list,
-                                             (u64 *)&eie, GFP_NOFS);
+                       ret = ulist_add_merge_ptr(refs, ref->parent,
+                                                 ref->inode_list,
+                                                 (void **)&eie, GFP_NOFS);
                        if (ret < 0)
                                goto out;
                        if (!ret && extent_item_pos) {
index 4794923c410cec258ae30aa929f3fc0bde5ba069..43527fd78825b690503347426118e09f76017c95 100644 (file)
@@ -84,12 +84,6 @@ struct btrfs_inode {
         */
        struct list_head delalloc_inodes;
 
-       /*
-        * list for tracking inodes that must be sent to disk before a
-        * rename or truncate commit
-        */
-       struct list_head ordered_operations;
-
        /* node for the red-black tree that links inodes in subvolume root */
        struct rb_node rb_node;
 
index aeab453b8e24482cd9f956a87882ea23549921f2..44ee5d2e52a41935828ac954ebeefe8ce17568e6 100644 (file)
@@ -280,9 +280,9 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
 
        WARN_ON(btrfs_header_generation(buf) > trans->transid);
        if (new_root_objectid == BTRFS_TREE_RELOC_OBJECTID)
-               ret = btrfs_inc_ref(trans, root, cow, 1, 1);
+               ret = btrfs_inc_ref(trans, root, cow, 1);
        else
-               ret = btrfs_inc_ref(trans, root, cow, 0, 1);
+               ret = btrfs_inc_ref(trans, root, cow, 0);
 
        if (ret)
                return ret;
@@ -1035,14 +1035,14 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
                if ((owner == root->root_key.objectid ||
                     root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) &&
                    !(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF)) {
-                       ret = btrfs_inc_ref(trans, root, buf, 1, 1);
+                       ret = btrfs_inc_ref(trans, root, buf, 1);
                        BUG_ON(ret); /* -ENOMEM */
 
                        if (root->root_key.objectid ==
                            BTRFS_TREE_RELOC_OBJECTID) {
-                               ret = btrfs_dec_ref(trans, root, buf, 0, 1);
+                               ret = btrfs_dec_ref(trans, root, buf, 0);
                                BUG_ON(ret); /* -ENOMEM */
-                               ret = btrfs_inc_ref(trans, root, cow, 1, 1);
+                               ret = btrfs_inc_ref(trans, root, cow, 1);
                                BUG_ON(ret); /* -ENOMEM */
                        }
                        new_flags |= BTRFS_BLOCK_FLAG_FULL_BACKREF;
@@ -1050,9 +1050,9 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
 
                        if (root->root_key.objectid ==
                            BTRFS_TREE_RELOC_OBJECTID)
-                               ret = btrfs_inc_ref(trans, root, cow, 1, 1);
+                               ret = btrfs_inc_ref(trans, root, cow, 1);
                        else
-                               ret = btrfs_inc_ref(trans, root, cow, 0, 1);
+                               ret = btrfs_inc_ref(trans, root, cow, 0);
                        BUG_ON(ret); /* -ENOMEM */
                }
                if (new_flags != 0) {
@@ -1069,11 +1069,11 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
                if (flags & BTRFS_BLOCK_FLAG_FULL_BACKREF) {
                        if (root->root_key.objectid ==
                            BTRFS_TREE_RELOC_OBJECTID)
-                               ret = btrfs_inc_ref(trans, root, cow, 1, 1);
+                               ret = btrfs_inc_ref(trans, root, cow, 1);
                        else
-                               ret = btrfs_inc_ref(trans, root, cow, 0, 1);
+                               ret = btrfs_inc_ref(trans, root, cow, 0);
                        BUG_ON(ret); /* -ENOMEM */
-                       ret = btrfs_dec_ref(trans, root, buf, 1, 1);
+                       ret = btrfs_dec_ref(trans, root, buf, 1);
                        BUG_ON(ret); /* -ENOMEM */
                }
                clean_tree_block(trans, root, buf);
index be91397f4e927de9e88f9e72f5559d8eae2e4d1a..8e29b614fe93d9b8cc22c9eb5d54377d617bb9e7 100644 (file)
@@ -3326,9 +3326,9 @@ int btrfs_reserve_extent(struct btrfs_root *root, u64 num_bytes,
                         u64 min_alloc_size, u64 empty_size, u64 hint_byte,
                         struct btrfs_key *ins, int is_data, int delalloc);
 int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
-                 struct extent_buffer *buf, int full_backref, int no_quota);
+                 struct extent_buffer *buf, int full_backref);
 int btrfs_dec_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
-                 struct extent_buffer *buf, int full_backref, int no_quota);
+                 struct extent_buffer *buf, int full_backref);
 int btrfs_set_disk_extent_flags(struct btrfs_trans_handle *trans,
                                struct btrfs_root *root,
                                u64 bytenr, u64 num_bytes, u64 flags,
index da775bfdebc989d905c931cde0f12bd00027abc9..a2e90f855d7d1e3cad650fc1d9691fd2de01cf65 100644 (file)
@@ -1395,8 +1395,8 @@ static int btrfs_wq_run_delayed_node(struct btrfs_delayed_root *delayed_root,
                return -ENOMEM;
 
        async_work->delayed_root = delayed_root;
-       btrfs_init_work(&async_work->work, btrfs_async_run_delayed_root,
-                       NULL, NULL);
+       btrfs_init_work(&async_work->work, btrfs_delayed_meta_helper,
+                       btrfs_async_run_delayed_root, NULL, NULL);
        async_work->nr = nr;
 
        btrfs_queue_work(root->fs_info->delayed_workers, &async_work->work);
index 08e65e9cf2aa97cb009249f5bf231d07e2c1f890..a1d36e62179c528041f292675e7452102863de45 100644 (file)
@@ -39,7 +39,6 @@
 #include "btrfs_inode.h"
 #include "volumes.h"
 #include "print-tree.h"
-#include "async-thread.h"
 #include "locking.h"
 #include "tree-log.h"
 #include "free-space-cache.h"
@@ -60,8 +59,6 @@ static void end_workqueue_fn(struct btrfs_work *work);
 static void free_fs_root(struct btrfs_root *root);
 static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info,
                                    int read_only);
-static void btrfs_destroy_ordered_operations(struct btrfs_transaction *t,
-                                            struct btrfs_root *root);
 static void btrfs_destroy_ordered_extents(struct btrfs_root *root);
 static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
                                      struct btrfs_root *root);
@@ -695,35 +692,41 @@ static void end_workqueue_bio(struct bio *bio, int err)
 {
        struct end_io_wq *end_io_wq = bio->bi_private;
        struct btrfs_fs_info *fs_info;
+       struct btrfs_workqueue *wq;
+       btrfs_work_func_t func;
 
        fs_info = end_io_wq->info;
        end_io_wq->error = err;
-       btrfs_init_work(&end_io_wq->work, end_workqueue_fn, NULL, NULL);
 
        if (bio->bi_rw & REQ_WRITE) {
-               if (end_io_wq->metadata == BTRFS_WQ_ENDIO_METADATA)
-                       btrfs_queue_work(fs_info->endio_meta_write_workers,
-                                        &end_io_wq->work);
-               else if (end_io_wq->metadata == BTRFS_WQ_ENDIO_FREE_SPACE)
-                       btrfs_queue_work(fs_info->endio_freespace_worker,
-                                        &end_io_wq->work);
-               else if (end_io_wq->metadata == BTRFS_WQ_ENDIO_RAID56)
-                       btrfs_queue_work(fs_info->endio_raid56_workers,
-                                        &end_io_wq->work);
-               else
-                       btrfs_queue_work(fs_info->endio_write_workers,
-                                        &end_io_wq->work);
+               if (end_io_wq->metadata == BTRFS_WQ_ENDIO_METADATA) {
+                       wq = fs_info->endio_meta_write_workers;
+                       func = btrfs_endio_meta_write_helper;
+               } else if (end_io_wq->metadata == BTRFS_WQ_ENDIO_FREE_SPACE) {
+                       wq = fs_info->endio_freespace_worker;
+                       func = btrfs_freespace_write_helper;
+               } else if (end_io_wq->metadata == BTRFS_WQ_ENDIO_RAID56) {
+                       wq = fs_info->endio_raid56_workers;
+                       func = btrfs_endio_raid56_helper;
+               } else {
+                       wq = fs_info->endio_write_workers;
+                       func = btrfs_endio_write_helper;
+               }
        } else {
-               if (end_io_wq->metadata == BTRFS_WQ_ENDIO_RAID56)
-                       btrfs_queue_work(fs_info->endio_raid56_workers,
-                                        &end_io_wq->work);
-               else if (end_io_wq->metadata)
-                       btrfs_queue_work(fs_info->endio_meta_workers,
-                                        &end_io_wq->work);
-               else
-                       btrfs_queue_work(fs_info->endio_workers,
-                                        &end_io_wq->work);
+               if (end_io_wq->metadata == BTRFS_WQ_ENDIO_RAID56) {
+                       wq = fs_info->endio_raid56_workers;
+                       func = btrfs_endio_raid56_helper;
+               } else if (end_io_wq->metadata) {
+                       wq = fs_info->endio_meta_workers;
+                       func = btrfs_endio_meta_helper;
+               } else {
+                       wq = fs_info->endio_workers;
+                       func = btrfs_endio_helper;
+               }
        }
+
+       btrfs_init_work(&end_io_wq->work, func, end_workqueue_fn, NULL, NULL);
+       btrfs_queue_work(wq, &end_io_wq->work);
 }
 
 /*
@@ -830,7 +833,7 @@ int btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct inode *inode,
        async->submit_bio_start = submit_bio_start;
        async->submit_bio_done = submit_bio_done;
 
-       btrfs_init_work(&async->work, run_one_async_start,
+       btrfs_init_work(&async->work, btrfs_worker_helper, run_one_async_start,
                        run_one_async_done, run_one_async_free);
 
        async->bio_flags = bio_flags;
@@ -3452,7 +3455,8 @@ static int write_all_supers(struct btrfs_root *root, int max_mirrors)
                btrfs_set_stack_device_generation(dev_item, 0);
                btrfs_set_stack_device_type(dev_item, dev->type);
                btrfs_set_stack_device_id(dev_item, dev->devid);
-               btrfs_set_stack_device_total_bytes(dev_item, dev->total_bytes);
+               btrfs_set_stack_device_total_bytes(dev_item,
+                                                  dev->disk_total_bytes);
                btrfs_set_stack_device_bytes_used(dev_item, dev->bytes_used);
                btrfs_set_stack_device_io_align(dev_item, dev->io_align);
                btrfs_set_stack_device_io_width(dev_item, dev->io_width);
@@ -3829,34 +3833,6 @@ static void btrfs_error_commit_super(struct btrfs_root *root)
        btrfs_cleanup_transaction(root);
 }
 
-static void btrfs_destroy_ordered_operations(struct btrfs_transaction *t,
-                                            struct btrfs_root *root)
-{
-       struct btrfs_inode *btrfs_inode;
-       struct list_head splice;
-
-       INIT_LIST_HEAD(&splice);
-
-       mutex_lock(&root->fs_info->ordered_operations_mutex);
-       spin_lock(&root->fs_info->ordered_root_lock);
-
-       list_splice_init(&t->ordered_operations, &splice);
-       while (!list_empty(&splice)) {
-               btrfs_inode = list_entry(splice.next, struct btrfs_inode,
-                                        ordered_operations);
-
-               list_del_init(&btrfs_inode->ordered_operations);
-               spin_unlock(&root->fs_info->ordered_root_lock);
-
-               btrfs_invalidate_inodes(btrfs_inode->root);
-
-               spin_lock(&root->fs_info->ordered_root_lock);
-       }
-
-       spin_unlock(&root->fs_info->ordered_root_lock);
-       mutex_unlock(&root->fs_info->ordered_operations_mutex);
-}
-
 static void btrfs_destroy_ordered_extents(struct btrfs_root *root)
 {
        struct btrfs_ordered_extent *ordered;
@@ -4093,8 +4069,6 @@ again:
 void btrfs_cleanup_one_transaction(struct btrfs_transaction *cur_trans,
                                   struct btrfs_root *root)
 {
-       btrfs_destroy_ordered_operations(cur_trans, root);
-
        btrfs_destroy_delayed_refs(cur_trans, root);
 
        cur_trans->state = TRANS_STATE_COMMIT_START;
index 813537f362f9ea318c05dd0c6a6030c2fbe08381..3efe1c3877bf34c4643ce99fb90d52fedda74d06 100644 (file)
@@ -552,7 +552,8 @@ static int cache_block_group(struct btrfs_block_group_cache *cache,
        caching_ctl->block_group = cache;
        caching_ctl->progress = cache->key.objectid;
        atomic_set(&caching_ctl->count, 1);
-       btrfs_init_work(&caching_ctl->work, caching_thread, NULL, NULL);
+       btrfs_init_work(&caching_ctl->work, btrfs_cache_helper,
+                       caching_thread, NULL, NULL);
 
        spin_lock(&cache->lock);
        /*
@@ -2749,8 +2750,8 @@ int btrfs_async_run_delayed_refs(struct btrfs_root *root,
                async->sync = 0;
        init_completion(&async->wait);
 
-       btrfs_init_work(&async->work, delayed_ref_async_start,
-                       NULL, NULL);
+       btrfs_init_work(&async->work, btrfs_extent_refs_helper,
+                       delayed_ref_async_start, NULL, NULL);
 
        btrfs_queue_work(root->fs_info->extent_workers, &async->work);
 
@@ -3057,7 +3058,7 @@ out:
 static int __btrfs_mod_ref(struct btrfs_trans_handle *trans,
                           struct btrfs_root *root,
                           struct extent_buffer *buf,
-                          int full_backref, int inc, int no_quota)
+                          int full_backref, int inc)
 {
        u64 bytenr;
        u64 num_bytes;
@@ -3111,7 +3112,7 @@ static int __btrfs_mod_ref(struct btrfs_trans_handle *trans,
                        key.offset -= btrfs_file_extent_offset(buf, fi);
                        ret = process_func(trans, root, bytenr, num_bytes,
                                           parent, ref_root, key.objectid,
-                                          key.offset, no_quota);
+                                          key.offset, 1);
                        if (ret)
                                goto fail;
                } else {
@@ -3119,7 +3120,7 @@ static int __btrfs_mod_ref(struct btrfs_trans_handle *trans,
                        num_bytes = btrfs_level_size(root, level - 1);
                        ret = process_func(trans, root, bytenr, num_bytes,
                                           parent, ref_root, level - 1, 0,
-                                          no_quota);
+                                          1);
                        if (ret)
                                goto fail;
                }
@@ -3130,15 +3131,15 @@ fail:
 }
 
 int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
-                 struct extent_buffer *buf, int full_backref, int no_quota)
+                 struct extent_buffer *buf, int full_backref)
 {
-       return __btrfs_mod_ref(trans, root, buf, full_backref, 1, no_quota);
+       return __btrfs_mod_ref(trans, root, buf, full_backref, 1);
 }
 
 int btrfs_dec_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
-                 struct extent_buffer *buf, int full_backref, int no_quota)
+                 struct extent_buffer *buf, int full_backref)
 {
-       return __btrfs_mod_ref(trans, root, buf, full_backref, 0, no_quota);
+       return __btrfs_mod_ref(trans, root, buf, full_backref, 0);
 }
 
 static int write_one_cache_group(struct btrfs_trans_handle *trans,
@@ -3586,13 +3587,7 @@ static u64 get_restripe_target(struct btrfs_fs_info *fs_info, u64 flags)
  */
 static u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags)
 {
-       /*
-        * we add in the count of missing devices because we want
-        * to make sure that any RAID levels on a degraded FS
-        * continue to be honored.
-        */
-       u64 num_devices = root->fs_info->fs_devices->rw_devices +
-               root->fs_info->fs_devices->missing_devices;
+       u64 num_devices = root->fs_info->fs_devices->rw_devices;
        u64 target;
        u64 tmp;
 
@@ -7478,6 +7473,220 @@ reada:
        wc->reada_slot = slot;
 }
 
+static int account_leaf_items(struct btrfs_trans_handle *trans,
+                             struct btrfs_root *root,
+                             struct extent_buffer *eb)
+{
+       int nr = btrfs_header_nritems(eb);
+       int i, extent_type, ret;
+       struct btrfs_key key;
+       struct btrfs_file_extent_item *fi;
+       u64 bytenr, num_bytes;
+
+       for (i = 0; i < nr; i++) {
+               btrfs_item_key_to_cpu(eb, &key, i);
+
+               if (key.type != BTRFS_EXTENT_DATA_KEY)
+                       continue;
+
+               fi = btrfs_item_ptr(eb, i, struct btrfs_file_extent_item);
+               /* filter out non qgroup-accountable extents  */
+               extent_type = btrfs_file_extent_type(eb, fi);
+
+               if (extent_type == BTRFS_FILE_EXTENT_INLINE)
+                       continue;
+
+               bytenr = btrfs_file_extent_disk_bytenr(eb, fi);
+               if (!bytenr)
+                       continue;
+
+               num_bytes = btrfs_file_extent_disk_num_bytes(eb, fi);
+
+               ret = btrfs_qgroup_record_ref(trans, root->fs_info,
+                                             root->objectid,
+                                             bytenr, num_bytes,
+                                             BTRFS_QGROUP_OPER_SUB_SUBTREE, 0);
+               if (ret)
+                       return ret;
+       }
+       return 0;
+}
+
+/*
+ * Walk up the tree from the bottom, freeing leaves and any interior
+ * nodes which have had all slots visited. If a node (leaf or
+ * interior) is freed, the node above it will have it's slot
+ * incremented. The root node will never be freed.
+ *
+ * At the end of this function, we should have a path which has all
+ * slots incremented to the next position for a search. If we need to
+ * read a new node it will be NULL and the node above it will have the
+ * correct slot selected for a later read.
+ *
+ * If we increment the root nodes slot counter past the number of
+ * elements, 1 is returned to signal completion of the search.
+ */
+static int adjust_slots_upwards(struct btrfs_root *root,
+                               struct btrfs_path *path, int root_level)
+{
+       int level = 0;
+       int nr, slot;
+       struct extent_buffer *eb;
+
+       if (root_level == 0)
+               return 1;
+
+       while (level <= root_level) {
+               eb = path->nodes[level];
+               nr = btrfs_header_nritems(eb);
+               path->slots[level]++;
+               slot = path->slots[level];
+               if (slot >= nr || level == 0) {
+                       /*
+                        * Don't free the root -  we will detect this
+                        * condition after our loop and return a
+                        * positive value for caller to stop walking the tree.
+                        */
+                       if (level != root_level) {
+                               btrfs_tree_unlock_rw(eb, path->locks[level]);
+                               path->locks[level] = 0;
+
+                               free_extent_buffer(eb);
+                               path->nodes[level] = NULL;
+                               path->slots[level] = 0;
+                       }
+               } else {
+                       /*
+                        * We have a valid slot to walk back down
+                        * from. Stop here so caller can process these
+                        * new nodes.
+                        */
+                       break;
+               }
+
+               level++;
+       }
+
+       eb = path->nodes[root_level];
+       if (path->slots[root_level] >= btrfs_header_nritems(eb))
+               return 1;
+
+       return 0;
+}
+
+/*
+ * root_eb is the subtree root and is locked before this function is called.
+ */
+static int account_shared_subtree(struct btrfs_trans_handle *trans,
+                                 struct btrfs_root *root,
+                                 struct extent_buffer *root_eb,
+                                 u64 root_gen,
+                                 int root_level)
+{
+       int ret = 0;
+       int level;
+       struct extent_buffer *eb = root_eb;
+       struct btrfs_path *path = NULL;
+
+       BUG_ON(root_level < 0 || root_level > BTRFS_MAX_LEVEL);
+       BUG_ON(root_eb == NULL);
+
+       if (!root->fs_info->quota_enabled)
+               return 0;
+
+       if (!extent_buffer_uptodate(root_eb)) {
+               ret = btrfs_read_buffer(root_eb, root_gen);
+               if (ret)
+                       goto out;
+       }
+
+       if (root_level == 0) {
+               ret = account_leaf_items(trans, root, root_eb);
+               goto out;
+       }
+
+       path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+
+       /*
+        * Walk down the tree.  Missing extent blocks are filled in as
+        * we go. Metadata is accounted every time we read a new
+        * extent block.
+        *
+        * When we reach a leaf, we account for file extent items in it,
+        * walk back up the tree (adjusting slot pointers as we go)
+        * and restart the search process.
+        */
+       extent_buffer_get(root_eb); /* For path */
+       path->nodes[root_level] = root_eb;
+       path->slots[root_level] = 0;
+       path->locks[root_level] = 0; /* so release_path doesn't try to unlock */
+walk_down:
+       level = root_level;
+       while (level >= 0) {
+               if (path->nodes[level] == NULL) {
+                       int child_bsize = root->nodesize;
+                       int parent_slot;
+                       u64 child_gen;
+                       u64 child_bytenr;
+
+                       /* We need to get child blockptr/gen from
+                        * parent before we can read it. */
+                       eb = path->nodes[level + 1];
+                       parent_slot = path->slots[level + 1];
+                       child_bytenr = btrfs_node_blockptr(eb, parent_slot);
+                       child_gen = btrfs_node_ptr_generation(eb, parent_slot);
+
+                       eb = read_tree_block(root, child_bytenr, child_bsize,
+                                            child_gen);
+                       if (!eb || !extent_buffer_uptodate(eb)) {
+                               ret = -EIO;
+                               goto out;
+                       }
+
+                       path->nodes[level] = eb;
+                       path->slots[level] = 0;
+
+                       btrfs_tree_read_lock(eb);
+                       btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK);
+                       path->locks[level] = BTRFS_READ_LOCK_BLOCKING;
+
+                       ret = btrfs_qgroup_record_ref(trans, root->fs_info,
+                                               root->objectid,
+                                               child_bytenr,
+                                               child_bsize,
+                                               BTRFS_QGROUP_OPER_SUB_SUBTREE,
+                                               0);
+                       if (ret)
+                               goto out;
+
+               }
+
+               if (level == 0) {
+                       ret = account_leaf_items(trans, root, path->nodes[level]);
+                       if (ret)
+                               goto out;
+
+                       /* Nonzero return here means we completed our search */
+                       ret = adjust_slots_upwards(root, path, root_level);
+                       if (ret)
+                               break;
+
+                       /* Restart search with new slots */
+                       goto walk_down;
+               }
+
+               level--;
+       }
+
+       ret = 0;
+out:
+       btrfs_free_path(path);
+
+       return ret;
+}
+
 /*
  * helper to process tree block while walking down the tree.
  *
@@ -7532,9 +7741,9 @@ static noinline int walk_down_proc(struct btrfs_trans_handle *trans,
        /* wc->stage == UPDATE_BACKREF */
        if (!(wc->flags[level] & flag)) {
                BUG_ON(!path->locks[level]);
-               ret = btrfs_inc_ref(trans, root, eb, 1, wc->for_reloc);
+               ret = btrfs_inc_ref(trans, root, eb, 1);
                BUG_ON(ret); /* -ENOMEM */
-               ret = btrfs_dec_ref(trans, root, eb, 0, wc->for_reloc);
+               ret = btrfs_dec_ref(trans, root, eb, 0);
                BUG_ON(ret); /* -ENOMEM */
                ret = btrfs_set_disk_extent_flags(trans, root, eb->start,
                                                  eb->len, flag,
@@ -7581,6 +7790,7 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
        int level = wc->level;
        int reada = 0;
        int ret = 0;
+       bool need_account = false;
 
        generation = btrfs_node_ptr_generation(path->nodes[level],
                                               path->slots[level]);
@@ -7626,6 +7836,7 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
 
        if (wc->stage == DROP_REFERENCE) {
                if (wc->refs[level - 1] > 1) {
+                       need_account = true;
                        if (level == 1 &&
                            (wc->flags[0] & BTRFS_BLOCK_FLAG_FULL_BACKREF))
                                goto skip;
@@ -7689,6 +7900,16 @@ skip:
                        parent = 0;
                }
 
+               if (need_account) {
+                       ret = account_shared_subtree(trans, root, next,
+                                                    generation, level - 1);
+                       if (ret) {
+                               printk_ratelimited(KERN_ERR "BTRFS: %s Error "
+                                       "%d accounting shared subtree. Quota "
+                                       "is out of sync, rescan required.\n",
+                                       root->fs_info->sb->s_id, ret);
+                       }
+               }
                ret = btrfs_free_extent(trans, root, bytenr, blocksize, parent,
                                root->root_key.objectid, level - 1, 0, 0);
                BUG_ON(ret); /* -ENOMEM */
@@ -7769,12 +7990,17 @@ static noinline int walk_up_proc(struct btrfs_trans_handle *trans,
        if (wc->refs[level] == 1) {
                if (level == 0) {
                        if (wc->flags[level] & BTRFS_BLOCK_FLAG_FULL_BACKREF)
-                               ret = btrfs_dec_ref(trans, root, eb, 1,
-                                                   wc->for_reloc);
+                               ret = btrfs_dec_ref(trans, root, eb, 1);
                        else
-                               ret = btrfs_dec_ref(trans, root, eb, 0,
-                                                   wc->for_reloc);
+                               ret = btrfs_dec_ref(trans, root, eb, 0);
                        BUG_ON(ret); /* -ENOMEM */
+                       ret = account_leaf_items(trans, root, eb);
+                       if (ret) {
+                               printk_ratelimited(KERN_ERR "BTRFS: %s Error "
+                                       "%d accounting leaf items. Quota "
+                                       "is out of sync, rescan required.\n",
+                                       root->fs_info->sb->s_id, ret);
+                       }
                }
                /* make block locked assertion in clean_tree_block happy */
                if (!path->locks[level] &&
@@ -7900,6 +8126,8 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
        int level;
        bool root_dropped = false;
 
+       btrfs_debug(root->fs_info, "Drop subvolume %llu", root->objectid);
+
        path = btrfs_alloc_path();
        if (!path) {
                err = -ENOMEM;
@@ -8025,6 +8253,24 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
                                goto out_end_trans;
                        }
 
+                       /*
+                        * Qgroup update accounting is run from
+                        * delayed ref handling. This usually works
+                        * out because delayed refs are normally the
+                        * only way qgroup updates are added. However,
+                        * we may have added updates during our tree
+                        * walk so run qgroups here to make sure we
+                        * don't lose any updates.
+                        */
+                       ret = btrfs_delayed_qgroup_accounting(trans,
+                                                             root->fs_info);
+                       if (ret)
+                               printk_ratelimited(KERN_ERR "BTRFS: Failure %d "
+                                                  "running qgroup updates "
+                                                  "during snapshot delete. "
+                                                  "Quota is out of sync, "
+                                                  "rescan required.\n", ret);
+
                        btrfs_end_transaction_throttle(trans, tree_root);
                        if (!for_reloc && btrfs_need_cleaner_sleep(root)) {
                                pr_debug("BTRFS: drop snapshot early exit\n");
@@ -8078,6 +8324,14 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
        }
        root_dropped = true;
 out_end_trans:
+       ret = btrfs_delayed_qgroup_accounting(trans, tree_root->fs_info);
+       if (ret)
+               printk_ratelimited(KERN_ERR "BTRFS: Failure %d "
+                                  "running qgroup updates "
+                                  "during snapshot delete. "
+                                  "Quota is out of sync, "
+                                  "rescan required.\n", ret);
+
        btrfs_end_transaction_throttle(trans, tree_root);
 out_free:
        kfree(wc);
@@ -8181,13 +8435,7 @@ static u64 update_block_group_flags(struct btrfs_root *root, u64 flags)
        if (stripped)
                return extended_to_chunk(stripped);
 
-       /*
-        * we add in the count of missing devices because we want
-        * to make sure that any RAID levels on a degraded FS
-        * continue to be honored.
-        */
-       num_devices = root->fs_info->fs_devices->rw_devices +
-               root->fs_info->fs_devices->missing_devices;
+       num_devices = root->fs_info->fs_devices->rw_devices;
 
        stripped = BTRFS_BLOCK_GROUP_RAID0 |
                BTRFS_BLOCK_GROUP_RAID5 | BTRFS_BLOCK_GROUP_RAID6 |
index 3e11aab9f391d9bce24c329694d62d3a48ced811..af0359dcf337dbfec421b49fedbb8b5d0ecbf8b8 100644 (file)
@@ -2532,6 +2532,7 @@ static void end_bio_extent_readpage(struct bio *bio, int err)
                                        test_bit(BIO_UPTODATE, &bio->bi_flags);
                                if (err)
                                        uptodate = 0;
+                               offset += len;
                                continue;
                        }
                }
@@ -4207,8 +4208,8 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                return -ENOMEM;
        path->leave_spinning = 1;
 
-       start = ALIGN(start, BTRFS_I(inode)->root->sectorsize);
-       len = ALIGN(len, BTRFS_I(inode)->root->sectorsize);
+       start = round_down(start, BTRFS_I(inode)->root->sectorsize);
+       len = round_up(max, BTRFS_I(inode)->root->sectorsize) - start;
 
        /*
         * lookup the last file extent.  We're not using i_size here
index f46cfe45d68629ff1a05406ef693cf73a6036381..54c84daec9b515f73f8f1178a1e4ea9485d20e3f 100644 (file)
@@ -756,7 +756,7 @@ again:
                                found_next = 1;
                        if (ret != 0)
                                goto insert;
-                       slot = 0;
+                       slot = path->slots[0];
                }
                btrfs_item_key_to_cpu(path->nodes[0], &found_key, slot);
                if (found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID ||
index 1f2b99cb55eaef682c51ae3c8b227e88aafbf7e7..36861b7a6757673189737024b62fcce9842bc3d0 100644 (file)
@@ -1838,6 +1838,8 @@ out:
 
 int btrfs_release_file(struct inode *inode, struct file *filp)
 {
+       if (filp->private_data)
+               btrfs_ioctl_trans_end(filp);
        /*
         * ordered_data_close is set by settattr when we are about to truncate
         * a file from a non-zero size to a zero size.  This tries to
@@ -1845,26 +1847,8 @@ int btrfs_release_file(struct inode *inode, struct file *filp)
         * application were using truncate to replace a file in place.
         */
        if (test_and_clear_bit(BTRFS_INODE_ORDERED_DATA_CLOSE,
-                              &BTRFS_I(inode)->runtime_flags)) {
-               struct btrfs_trans_handle *trans;
-               struct btrfs_root *root = BTRFS_I(inode)->root;
-
-               /*
-                * We need to block on a committing transaction to keep us from
-                * throwing a ordered operation on to the list and causing
-                * something like sync to deadlock trying to flush out this
-                * inode.
-                */
-               trans = btrfs_start_transaction(root, 0);
-               if (IS_ERR(trans))
-                       return PTR_ERR(trans);
-               btrfs_add_ordered_operation(trans, BTRFS_I(inode)->root, inode);
-               btrfs_end_transaction(trans, root);
-               if (inode->i_size > BTRFS_ORDERED_OPERATIONS_FLUSH_LIMIT)
+                              &BTRFS_I(inode)->runtime_flags))
                        filemap_flush(inode->i_mapping);
-       }
-       if (filp->private_data)
-               btrfs_ioctl_trans_end(filp);
        return 0;
 }
 
@@ -2112,10 +2096,9 @@ static int fill_holes(struct btrfs_trans_handle *trans, struct inode *inode,
                goto out;
        }
 
-       if (hole_mergeable(inode, leaf, path->slots[0]+1, offset, end)) {
+       if (hole_mergeable(inode, leaf, path->slots[0], offset, end)) {
                u64 num_bytes;
 
-               path->slots[0]++;
                key.offset = offset;
                btrfs_set_item_key_safe(root, path, &key);
                fi = btrfs_item_ptr(leaf, path->slots[0],
@@ -2240,7 +2223,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
                goto out_only_mutex;
        }
 
-       lockstart = round_up(offset , BTRFS_I(inode)->root->sectorsize);
+       lockstart = round_up(offset, BTRFS_I(inode)->root->sectorsize);
        lockend = round_down(offset + len,
                             BTRFS_I(inode)->root->sectorsize) - 1;
        same_page = ((offset >> PAGE_CACHE_SHIFT) ==
@@ -2301,7 +2284,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
                                                tail_start + tail_len, 0, 1);
                                if (ret)
                                        goto out_only_mutex;
-                               }
+                       }
                }
        }
 
index 3183742d6f0d74d131c16e29dde59205f3e7f8a4..9c194bd74d6e513c075b077b62ee1754cd02e966 100644 (file)
@@ -709,6 +709,18 @@ retry:
                                unlock_extent(io_tree, async_extent->start,
                                              async_extent->start +
                                              async_extent->ram_size - 1);
+
+                               /*
+                                * we need to redirty the pages if we decide to
+                                * fallback to uncompressed IO, otherwise we
+                                * will not submit these pages down to lower
+                                * layers.
+                                */
+                               extent_range_redirty_for_io(inode,
+                                               async_extent->start,
+                                               async_extent->start +
+                                               async_extent->ram_size - 1);
+
                                goto retry;
                        }
                        goto out_free;
@@ -1084,8 +1096,10 @@ static int cow_file_range_async(struct inode *inode, struct page *locked_page,
                async_cow->end = cur_end;
                INIT_LIST_HEAD(&async_cow->extents);
 
-               btrfs_init_work(&async_cow->work, async_cow_start,
-                               async_cow_submit, async_cow_free);
+               btrfs_init_work(&async_cow->work,
+                               btrfs_delalloc_helper,
+                               async_cow_start, async_cow_submit,
+                               async_cow_free);
 
                nr_pages = (cur_end - start + PAGE_CACHE_SIZE) >>
                        PAGE_CACHE_SHIFT;
@@ -1869,7 +1883,8 @@ static int btrfs_writepage_start_hook(struct page *page, u64 start, u64 end)
 
        SetPageChecked(page);
        page_cache_get(page);
-       btrfs_init_work(&fixup->work, btrfs_writepage_fixup_worker, NULL, NULL);
+       btrfs_init_work(&fixup->work, btrfs_fixup_helper,
+                       btrfs_writepage_fixup_worker, NULL, NULL);
        fixup->page = page;
        btrfs_queue_work(root->fs_info->fixup_workers, &fixup->work);
        return -EBUSY;
@@ -2810,7 +2825,8 @@ static int btrfs_writepage_end_io_hook(struct page *page, u64 start, u64 end,
        struct inode *inode = page->mapping->host;
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct btrfs_ordered_extent *ordered_extent = NULL;
-       struct btrfs_workqueue *workers;
+       struct btrfs_workqueue *wq;
+       btrfs_work_func_t func;
 
        trace_btrfs_writepage_end_io_hook(page, start, end, uptodate);
 
@@ -2819,13 +2835,17 @@ static int btrfs_writepage_end_io_hook(struct page *page, u64 start, u64 end,
                                            end - start + 1, uptodate))
                return 0;
 
-       btrfs_init_work(&ordered_extent->work, finish_ordered_fn, NULL, NULL);
+       if (btrfs_is_free_space_inode(inode)) {
+               wq = root->fs_info->endio_freespace_worker;
+               func = btrfs_freespace_write_helper;
+       } else {
+               wq = root->fs_info->endio_write_workers;
+               func = btrfs_endio_write_helper;
+       }
 
-       if (btrfs_is_free_space_inode(inode))
-               workers = root->fs_info->endio_freespace_worker;
-       else
-               workers = root->fs_info->endio_write_workers;
-       btrfs_queue_work(workers, &ordered_extent->work);
+       btrfs_init_work(&ordered_extent->work, func, finish_ordered_fn, NULL,
+                       NULL);
+       btrfs_queue_work(wq, &ordered_extent->work);
 
        return 0;
 }
@@ -4662,6 +4682,11 @@ static void evict_inode_truncate_pages(struct inode *inode)
                clear_bit(EXTENT_FLAG_LOGGING, &em->flags);
                remove_extent_mapping(map_tree, em);
                free_extent_map(em);
+               if (need_resched()) {
+                       write_unlock(&map_tree->lock);
+                       cond_resched();
+                       write_lock(&map_tree->lock);
+               }
        }
        write_unlock(&map_tree->lock);
 
@@ -4684,6 +4709,7 @@ static void evict_inode_truncate_pages(struct inode *inode)
                                 &cached_state, GFP_NOFS);
                free_extent_state(state);
 
+               cond_resched();
                spin_lock(&io_tree->lock);
        }
        spin_unlock(&io_tree->lock);
@@ -5169,6 +5195,42 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry)
                        iput(inode);
                        inode = ERR_PTR(ret);
                }
+               /*
+                * If orphan cleanup did remove any orphans, it means the tree
+                * was modified and therefore the commit root is not the same as
+                * the current root anymore. This is a problem, because send
+                * uses the commit root and therefore can see inode items that
+                * don't exist in the current root anymore, and for example make
+                * calls to btrfs_iget, which will do tree lookups based on the
+                * current root and not on the commit root. Those lookups will
+                * fail, returning a -ESTALE error, and making send fail with
+                * that error. So make sure a send does not see any orphans we
+                * have just removed, and that it will see the same inodes
+                * regardless of whether a transaction commit happened before
+                * it started (meaning that the commit root will be the same as
+                * the current root) or not.
+                */
+               if (sub_root->node != sub_root->commit_root) {
+                       u64 sub_flags = btrfs_root_flags(&sub_root->root_item);
+
+                       if (sub_flags & BTRFS_ROOT_SUBVOL_RDONLY) {
+                               struct extent_buffer *eb;
+
+                               /*
+                                * Assert we can't have races between dentry
+                                * lookup called through the snapshot creation
+                                * ioctl and the VFS.
+                                */
+                               ASSERT(mutex_is_locked(&dir->i_mutex));
+
+                               down_write(&root->fs_info->commit_root_sem);
+                               eb = sub_root->commit_root;
+                               sub_root->commit_root =
+                                       btrfs_root_node(sub_root);
+                               up_write(&root->fs_info->commit_root_sem);
+                               free_extent_buffer(eb);
+                       }
+               }
        }
 
        return inode;
@@ -5593,6 +5655,13 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
                return ERR_PTR(-ENOMEM);
        }
 
+       /*
+        * O_TMPFILE, set link count to 0, so that after this point,
+        * we fill in an inode item with the correct link count.
+        */
+       if (!name)
+               set_nlink(inode, 0);
+
        /*
         * we have to initialize this early, so we can reclaim the inode
         * number if we fail afterwards in this function.
@@ -6085,14 +6154,14 @@ out_fail:
 static int merge_extent_mapping(struct extent_map_tree *em_tree,
                                struct extent_map *existing,
                                struct extent_map *em,
-                               u64 map_start, u64 map_len)
+                               u64 map_start)
 {
        u64 start_diff;
 
        BUG_ON(map_start < em->start || map_start >= extent_map_end(em));
        start_diff = map_start - em->start;
        em->start = map_start;
-       em->len = map_len;
+       em->len = existing->start - em->start;
        if (em->block_start < EXTENT_MAP_LAST_BYTE &&
            !test_bit(EXTENT_FLAG_COMPRESSED, &em->flags)) {
                em->block_start += start_diff;
@@ -6263,6 +6332,8 @@ next:
                        goto not_found;
                if (start + len <= found_key.offset)
                        goto not_found;
+               if (start > found_key.offset)
+                       goto next;
                em->start = start;
                em->orig_start = start;
                em->len = found_key.offset - start;
@@ -6378,8 +6449,7 @@ insert:
                                                         em->len);
                        if (existing) {
                                err = merge_extent_mapping(em_tree, existing,
-                                                          em, start,
-                                                          root->sectorsize);
+                                                          em, start);
                                free_extent_map(existing);
                                if (err) {
                                        free_extent_map(em);
@@ -7146,7 +7216,8 @@ again:
        if (!ret)
                goto out_test;
 
-       btrfs_init_work(&ordered->work, finish_ordered_fn, NULL, NULL);
+       btrfs_init_work(&ordered->work, btrfs_endio_write_helper,
+                       finish_ordered_fn, NULL, NULL);
        btrfs_queue_work(root->fs_info->endio_write_workers,
                         &ordered->work);
 out_test:
@@ -7294,10 +7365,8 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip,
        map_length = orig_bio->bi_iter.bi_size;
        ret = btrfs_map_block(root->fs_info, rw, start_sector << 9,
                              &map_length, NULL, 0);
-       if (ret) {
-               bio_put(orig_bio);
+       if (ret)
                return -EIO;
-       }
 
        if (map_length >= orig_bio->bi_iter.bi_size) {
                bio = orig_bio;
@@ -7314,6 +7383,7 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip,
        bio = btrfs_dio_bio_alloc(orig_bio->bi_bdev, start_sector, GFP_NOFS);
        if (!bio)
                return -ENOMEM;
+
        bio->bi_private = dip;
        bio->bi_end_io = btrfs_end_dio_bio;
        atomic_inc(&dip->pending_bios);
@@ -7522,7 +7592,8 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb,
        count = iov_iter_count(iter);
        if (test_bit(BTRFS_INODE_HAS_ASYNC_EXTENT,
                     &BTRFS_I(inode)->runtime_flags))
-               filemap_fdatawrite_range(inode->i_mapping, offset, count);
+               filemap_fdatawrite_range(inode->i_mapping, offset,
+                                        offset + count - 1);
 
        if (rw & WRITE) {
                /*
@@ -7938,27 +8009,6 @@ static int btrfs_truncate(struct inode *inode)
                                      min_size);
        BUG_ON(ret);
 
-       /*
-        * setattr is responsible for setting the ordered_data_close flag,
-        * but that is only tested during the last file release.  That
-        * could happen well after the next commit, leaving a great big
-        * window where new writes may get lost if someone chooses to write
-        * to this file after truncating to zero
-        *
-        * The inode doesn't have any dirty data here, and so if we commit
-        * this is a noop.  If someone immediately starts writing to the inode
-        * it is very likely we'll catch some of their writes in this
-        * transaction, and the commit will find this file on the ordered
-        * data list with good things to send down.
-        *
-        * This is a best effort solution, there is still a window where
-        * using truncate to replace the contents of the file will
-        * end up with a zero length file after a crash.
-        */
-       if (inode->i_size == 0 && test_bit(BTRFS_INODE_ORDERED_DATA_CLOSE,
-                                          &BTRFS_I(inode)->runtime_flags))
-               btrfs_add_ordered_operation(trans, root, inode);
-
        /*
         * So if we truncate and then write and fsync we normally would just
         * write the extents that changed, which is a problem if we need to
@@ -8106,7 +8156,6 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
        mutex_init(&ei->delalloc_mutex);
        btrfs_ordered_inode_tree_init(&ei->ordered_tree);
        INIT_LIST_HEAD(&ei->delalloc_inodes);
-       INIT_LIST_HEAD(&ei->ordered_operations);
        RB_CLEAR_NODE(&ei->rb_node);
 
        return inode;
@@ -8146,17 +8195,6 @@ void btrfs_destroy_inode(struct inode *inode)
        if (!root)
                goto free;
 
-       /*
-        * Make sure we're properly removed from the ordered operation
-        * lists.
-        */
-       smp_mb();
-       if (!list_empty(&BTRFS_I(inode)->ordered_operations)) {
-               spin_lock(&root->fs_info->ordered_root_lock);
-               list_del_init(&BTRFS_I(inode)->ordered_operations);
-               spin_unlock(&root->fs_info->ordered_root_lock);
-       }
-
        if (test_bit(BTRFS_INODE_HAS_ORPHAN_ITEM,
                     &BTRFS_I(inode)->runtime_flags)) {
                btrfs_info(root->fs_info, "inode %llu still on the orphan list",
@@ -8338,12 +8376,10 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        ret = 0;
 
        /*
-        * we're using rename to replace one file with another.
-        * and the replacement file is large.  Start IO on it now so
-        * we don't add too much work to the end of the transaction
+        * we're using rename to replace one file with another.  Start IO on it
+        * now so  we don't add too much work to the end of the transaction
         */
-       if (new_inode && S_ISREG(old_inode->i_mode) && new_inode->i_size &&
-           old_inode->i_size > BTRFS_ORDERED_OPERATIONS_FLUSH_LIMIT)
+       if (new_inode && S_ISREG(old_inode->i_mode) && new_inode->i_size)
                filemap_flush(old_inode->i_mapping);
 
        /* close the racy window with snapshot create/destroy ioctl */
@@ -8391,12 +8427,6 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                 */
                btrfs_pin_log_trans(root);
        }
-       /*
-        * make sure the inode gets flushed if it is replacing
-        * something.
-        */
-       if (new_inode && new_inode->i_size && S_ISREG(old_inode->i_mode))
-               btrfs_add_ordered_operation(trans, root, old_inode);
 
        inode_inc_iversion(old_dir);
        inode_inc_iversion(new_dir);
@@ -8524,7 +8554,9 @@ struct btrfs_delalloc_work *btrfs_alloc_delalloc_work(struct inode *inode,
        work->inode = inode;
        work->wait = wait;
        work->delay_iput = delay_iput;
-       btrfs_init_work(&work->work, btrfs_run_delalloc_work, NULL, NULL);
+       WARN_ON_ONCE(!inode);
+       btrfs_init_work(&work->work, btrfs_flush_delalloc_helper,
+                       btrfs_run_delalloc_work, NULL, NULL);
 
        return work;
 }
@@ -9008,6 +9040,14 @@ static int btrfs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
        if (ret)
                goto out;
 
+       /*
+        * We set number of links to 0 in btrfs_new_inode(), and here we set
+        * it to 1 because d_tmpfile() will issue a warning if the count is 0,
+        * through:
+        *
+        *    d_tmpfile() -> inode_dec_link_count() -> drop_nlink()
+        */
+       set_nlink(inode, 1);
        d_tmpfile(dentry, inode);
        mark_inode_dirty(inode);
 
index 47aceb494d1d456da8940c5e7a1d3eed3fa4adc5..fce6fd0e3f50c729adcf278b1b2a13bd2ede1494 100644 (file)
@@ -711,39 +711,6 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
        if (ret)
                goto fail;
 
-       ret = btrfs_orphan_cleanup(pending_snapshot->snap);
-       if (ret)
-               goto fail;
-
-       /*
-        * If orphan cleanup did remove any orphans, it means the tree was
-        * modified and therefore the commit root is not the same as the
-        * current root anymore. This is a problem, because send uses the
-        * commit root and therefore can see inode items that don't exist
-        * in the current root anymore, and for example make calls to
-        * btrfs_iget, which will do tree lookups based on the current root
-        * and not on the commit root. Those lookups will fail, returning a
-        * -ESTALE error, and making send fail with that error. So make sure
-        * a send does not see any orphans we have just removed, and that it
-        * will see the same inodes regardless of whether a transaction
-        * commit happened before it started (meaning that the commit root
-        * will be the same as the current root) or not.
-        */
-       if (readonly && pending_snapshot->snap->node !=
-           pending_snapshot->snap->commit_root) {
-               trans = btrfs_join_transaction(pending_snapshot->snap);
-               if (IS_ERR(trans) && PTR_ERR(trans) != -ENOENT) {
-                       ret = PTR_ERR(trans);
-                       goto fail;
-               }
-               if (!IS_ERR(trans)) {
-                       ret = btrfs_commit_transaction(trans,
-                                                      pending_snapshot->snap);
-                       if (ret)
-                               goto fail;
-               }
-       }
-
        inode = btrfs_lookup_dentry(dentry->d_parent->d_inode, dentry);
        if (IS_ERR(inode)) {
                ret = PTR_ERR(inode);
@@ -3527,7 +3494,8 @@ process_slot:
                        btrfs_mark_buffer_dirty(leaf);
                        btrfs_release_path(path);
 
-                       last_dest_end = new_key.offset + datal;
+                       last_dest_end = ALIGN(new_key.offset + datal,
+                                             root->sectorsize);
                        ret = clone_finish_inode_update(trans, inode,
                                                        last_dest_end,
                                                        destoff, olen);
index 7187b14faa6cd0c1c846fcfb155f431102ce8bad..ac734ec4cc20ecbc47bc1b495b75021b4c699edf 100644 (file)
@@ -571,18 +571,6 @@ void btrfs_remove_ordered_extent(struct inode *inode,
 
        trace_btrfs_ordered_extent_remove(inode, entry);
 
-       /*
-        * we have no more ordered extents for this inode and
-        * no dirty pages.  We can safely remove it from the
-        * list of ordered extents
-        */
-       if (RB_EMPTY_ROOT(&tree->tree) &&
-           !mapping_tagged(inode->i_mapping, PAGECACHE_TAG_DIRTY)) {
-               spin_lock(&root->fs_info->ordered_root_lock);
-               list_del_init(&BTRFS_I(inode)->ordered_operations);
-               spin_unlock(&root->fs_info->ordered_root_lock);
-       }
-
        if (!root->nr_ordered_extents) {
                spin_lock(&root->fs_info->ordered_root_lock);
                BUG_ON(list_empty(&root->ordered_root));
@@ -627,6 +615,7 @@ int btrfs_wait_ordered_extents(struct btrfs_root *root, int nr)
                spin_unlock(&root->ordered_extent_lock);
 
                btrfs_init_work(&ordered->flush_work,
+                               btrfs_flush_delalloc_helper,
                                btrfs_run_ordered_extent_work, NULL, NULL);
                list_add_tail(&ordered->work_list, &works);
                btrfs_queue_work(root->fs_info->flush_workers,
@@ -686,81 +675,6 @@ void btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, int nr)
        mutex_unlock(&fs_info->ordered_operations_mutex);
 }
 
-/*
- * this is used during transaction commit to write all the inodes
- * added to the ordered operation list.  These files must be fully on
- * disk before the transaction commits.
- *
- * we have two modes here, one is to just start the IO via filemap_flush
- * and the other is to wait for all the io.  When we wait, we have an
- * extra check to make sure the ordered operation list really is empty
- * before we return
- */
-int btrfs_run_ordered_operations(struct btrfs_trans_handle *trans,
-                                struct btrfs_root *root, int wait)
-{
-       struct btrfs_inode *btrfs_inode;
-       struct inode *inode;
-       struct btrfs_transaction *cur_trans = trans->transaction;
-       struct list_head splice;
-       struct list_head works;
-       struct btrfs_delalloc_work *work, *next;
-       int ret = 0;
-
-       INIT_LIST_HEAD(&splice);
-       INIT_LIST_HEAD(&works);
-
-       mutex_lock(&root->fs_info->ordered_extent_flush_mutex);
-       spin_lock(&root->fs_info->ordered_root_lock);
-       list_splice_init(&cur_trans->ordered_operations, &splice);
-       while (!list_empty(&splice)) {
-               btrfs_inode = list_entry(splice.next, struct btrfs_inode,
-                                  ordered_operations);
-               inode = &btrfs_inode->vfs_inode;
-
-               list_del_init(&btrfs_inode->ordered_operations);
-
-               /*
-                * the inode may be getting freed (in sys_unlink path).
-                */
-               inode = igrab(inode);
-               if (!inode)
-                       continue;
-
-               if (!wait)
-                       list_add_tail(&BTRFS_I(inode)->ordered_operations,
-                                     &cur_trans->ordered_operations);
-               spin_unlock(&root->fs_info->ordered_root_lock);
-
-               work = btrfs_alloc_delalloc_work(inode, wait, 1);
-               if (!work) {
-                       spin_lock(&root->fs_info->ordered_root_lock);
-                       if (list_empty(&BTRFS_I(inode)->ordered_operations))
-                               list_add_tail(&btrfs_inode->ordered_operations,
-                                             &splice);
-                       list_splice_tail(&splice,
-                                        &cur_trans->ordered_operations);
-                       spin_unlock(&root->fs_info->ordered_root_lock);
-                       ret = -ENOMEM;
-                       goto out;
-               }
-               list_add_tail(&work->list, &works);
-               btrfs_queue_work(root->fs_info->flush_workers,
-                                &work->work);
-
-               cond_resched();
-               spin_lock(&root->fs_info->ordered_root_lock);
-       }
-       spin_unlock(&root->fs_info->ordered_root_lock);
-out:
-       list_for_each_entry_safe(work, next, &works, list) {
-               list_del_init(&work->list);
-               btrfs_wait_and_free_delalloc_work(work);
-       }
-       mutex_unlock(&root->fs_info->ordered_extent_flush_mutex);
-       return ret;
-}
-
 /*
  * Used to start IO or wait for a given ordered extent to finish.
  *
@@ -1120,42 +1034,6 @@ out:
        return index;
 }
 
-
-/*
- * add a given inode to the list of inodes that must be fully on
- * disk before a transaction commit finishes.
- *
- * This basically gives us the ext3 style data=ordered mode, and it is mostly
- * used to make sure renamed files are fully on disk.
- *
- * It is a noop if the inode is already fully on disk.
- *
- * If trans is not null, we'll do a friendly check for a transaction that
- * is already flushing things and force the IO down ourselves.
- */
-void btrfs_add_ordered_operation(struct btrfs_trans_handle *trans,
-                                struct btrfs_root *root, struct inode *inode)
-{
-       struct btrfs_transaction *cur_trans = trans->transaction;
-       u64 last_mod;
-
-       last_mod = max(BTRFS_I(inode)->generation, BTRFS_I(inode)->last_trans);
-
-       /*
-        * if this file hasn't been changed since the last transaction
-        * commit, we can safely return without doing anything
-        */
-       if (last_mod <= root->fs_info->last_trans_committed)
-               return;
-
-       spin_lock(&root->fs_info->ordered_root_lock);
-       if (list_empty(&BTRFS_I(inode)->ordered_operations)) {
-               list_add_tail(&BTRFS_I(inode)->ordered_operations,
-                             &cur_trans->ordered_operations);
-       }
-       spin_unlock(&root->fs_info->ordered_root_lock);
-}
-
 int __init ordered_data_init(void)
 {
        btrfs_ordered_extent_cache = kmem_cache_create("btrfs_ordered_extent",
index 246897058efb009ffd521cee2d61cb60fc0bde0f..d81a274d621ee47cf2510b2323997d67567a3a88 100644 (file)
@@ -190,11 +190,6 @@ int btrfs_ordered_update_i_size(struct inode *inode, u64 offset,
                                struct btrfs_ordered_extent *ordered);
 int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr,
                           u32 *sum, int len);
-int btrfs_run_ordered_operations(struct btrfs_trans_handle *trans,
-                                struct btrfs_root *root, int wait);
-void btrfs_add_ordered_operation(struct btrfs_trans_handle *trans,
-                                struct btrfs_root *root,
-                                struct inode *inode);
 int btrfs_wait_ordered_extents(struct btrfs_root *root, int nr);
 void btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, int nr);
 void btrfs_get_logged_extents(struct inode *inode,
index 98cb6b2630f9aac60972b5aea3c372e9e99eeba5..ded5c601d9162a7699a3fa4802a8c9df9bd37722 100644 (file)
@@ -1201,6 +1201,50 @@ out:
        mutex_unlock(&fs_info->qgroup_ioctl_lock);
        return ret;
 }
+
+static int comp_oper_exist(struct btrfs_qgroup_operation *oper1,
+                          struct btrfs_qgroup_operation *oper2)
+{
+       /*
+        * Ignore seq and type here, we're looking for any operation
+        * at all related to this extent on that root.
+        */
+       if (oper1->bytenr < oper2->bytenr)
+               return -1;
+       if (oper1->bytenr > oper2->bytenr)
+               return 1;
+       if (oper1->ref_root < oper2->ref_root)
+               return -1;
+       if (oper1->ref_root > oper2->ref_root)
+               return 1;
+       return 0;
+}
+
+static int qgroup_oper_exists(struct btrfs_fs_info *fs_info,
+                             struct btrfs_qgroup_operation *oper)
+{
+       struct rb_node *n;
+       struct btrfs_qgroup_operation *cur;
+       int cmp;
+
+       spin_lock(&fs_info->qgroup_op_lock);
+       n = fs_info->qgroup_op_tree.rb_node;
+       while (n) {
+               cur = rb_entry(n, struct btrfs_qgroup_operation, n);
+               cmp = comp_oper_exist(cur, oper);
+               if (cmp < 0) {
+                       n = n->rb_right;
+               } else if (cmp) {
+                       n = n->rb_left;
+               } else {
+                       spin_unlock(&fs_info->qgroup_op_lock);
+                       return -EEXIST;
+               }
+       }
+       spin_unlock(&fs_info->qgroup_op_lock);
+       return 0;
+}
+
 static int comp_oper(struct btrfs_qgroup_operation *oper1,
                     struct btrfs_qgroup_operation *oper2)
 {
@@ -1290,6 +1334,23 @@ int btrfs_qgroup_record_ref(struct btrfs_trans_handle *trans,
        oper->seq = atomic_inc_return(&fs_info->qgroup_op_seq);
        INIT_LIST_HEAD(&oper->elem.list);
        oper->elem.seq = 0;
+
+       if (type == BTRFS_QGROUP_OPER_SUB_SUBTREE) {
+               /*
+                * If any operation for this bytenr/ref_root combo
+                * exists, then we know it's not exclusively owned and
+                * shouldn't be queued up.
+                *
+                * This also catches the case where we have a cloned
+                * extent that gets queued up multiple times during
+                * drop snapshot.
+                */
+               if (qgroup_oper_exists(fs_info, oper)) {
+                       kfree(oper);
+                       return 0;
+               }
+       }
+
        ret = insert_qgroup_oper(fs_info, oper);
        if (ret) {
                /* Shouldn't happen so have an assert for developers */
@@ -1883,6 +1944,111 @@ out:
        return ret;
 }
 
+/*
+ * Process a reference to a shared subtree. This type of operation is
+ * queued during snapshot removal when we encounter extents which are
+ * shared between more than one root.
+ */
+static int qgroup_subtree_accounting(struct btrfs_trans_handle *trans,
+                                    struct btrfs_fs_info *fs_info,
+                                    struct btrfs_qgroup_operation *oper)
+{
+       struct ulist *roots = NULL;
+       struct ulist_node *unode;
+       struct ulist_iterator uiter;
+       struct btrfs_qgroup_list *glist;
+       struct ulist *parents;
+       int ret = 0;
+       int err;
+       struct btrfs_qgroup *qg;
+       u64 root_obj = 0;
+       struct seq_list elem = {};
+
+       parents = ulist_alloc(GFP_NOFS);
+       if (!parents)
+               return -ENOMEM;
+
+       btrfs_get_tree_mod_seq(fs_info, &elem);
+       ret = btrfs_find_all_roots(trans, fs_info, oper->bytenr,
+                                  elem.seq, &roots);
+       btrfs_put_tree_mod_seq(fs_info, &elem);
+       if (ret < 0)
+               goto out;
+
+       if (roots->nnodes != 1)
+               goto out;
+
+       ULIST_ITER_INIT(&uiter);
+       unode = ulist_next(roots, &uiter); /* Only want 1 so no need to loop */
+       /*
+        * If we find our ref root then that means all refs
+        * this extent has to the root have not yet been
+        * deleted. In that case, we do nothing and let the
+        * last ref for this bytenr drive our update.
+        *
+        * This can happen for example if an extent is
+        * referenced multiple times in a snapshot (clone,
+        * etc). If we are in the middle of snapshot removal,
+        * queued updates for such an extent will find the
+        * root if we have not yet finished removing the
+        * snapshot.
+        */
+       if (unode->val == oper->ref_root)
+               goto out;
+
+       root_obj = unode->val;
+       BUG_ON(!root_obj);
+
+       spin_lock(&fs_info->qgroup_lock);
+       qg = find_qgroup_rb(fs_info, root_obj);
+       if (!qg)
+               goto out_unlock;
+
+       qg->excl += oper->num_bytes;
+       qg->excl_cmpr += oper->num_bytes;
+       qgroup_dirty(fs_info, qg);
+
+       /*
+        * Adjust counts for parent groups. First we find all
+        * parents, then in the 2nd loop we do the adjustment
+        * while adding parents of the parents to our ulist.
+        */
+       list_for_each_entry(glist, &qg->groups, next_group) {
+               err = ulist_add(parents, glist->group->qgroupid,
+                               ptr_to_u64(glist->group), GFP_ATOMIC);
+               if (err < 0) {
+                       ret = err;
+                       goto out_unlock;
+               }
+       }
+
+       ULIST_ITER_INIT(&uiter);
+       while ((unode = ulist_next(parents, &uiter))) {
+               qg = u64_to_ptr(unode->aux);
+               qg->excl += oper->num_bytes;
+               qg->excl_cmpr += oper->num_bytes;
+               qgroup_dirty(fs_info, qg);
+
+               /* Add any parents of the parents */
+               list_for_each_entry(glist, &qg->groups, next_group) {
+                       err = ulist_add(parents, glist->group->qgroupid,
+                                       ptr_to_u64(glist->group), GFP_ATOMIC);
+                       if (err < 0) {
+                               ret = err;
+                               goto out_unlock;
+                       }
+               }
+       }
+
+out_unlock:
+       spin_unlock(&fs_info->qgroup_lock);
+
+out:
+       ulist_free(roots);
+       ulist_free(parents);
+       return ret;
+}
+
 /*
  * btrfs_qgroup_account_ref is called for every ref that is added to or deleted
  * from the fs. First, all roots referencing the extent are searched, and
@@ -1920,6 +2086,9 @@ static int btrfs_qgroup_account(struct btrfs_trans_handle *trans,
        case BTRFS_QGROUP_OPER_SUB_SHARED:
                ret = qgroup_shared_accounting(trans, fs_info, oper);
                break;
+       case BTRFS_QGROUP_OPER_SUB_SUBTREE:
+               ret = qgroup_subtree_accounting(trans, fs_info, oper);
+               break;
        default:
                ASSERT(0);
        }
@@ -2551,6 +2720,7 @@ qgroup_rescan_init(struct btrfs_fs_info *fs_info, u64 progress_objectid,
        memset(&fs_info->qgroup_rescan_work, 0,
               sizeof(fs_info->qgroup_rescan_work));
        btrfs_init_work(&fs_info->qgroup_rescan_work,
+                       btrfs_qgroup_rescan_helper,
                        btrfs_qgroup_rescan_worker, NULL, NULL);
 
        if (ret) {
index 5952ff1fbd7a5290d8fe563d8463100af58098d2..18cc68ca309054e84ce8248d78059fe3170be3ac 100644 (file)
@@ -44,6 +44,7 @@ enum btrfs_qgroup_operation_type {
        BTRFS_QGROUP_OPER_ADD_SHARED,
        BTRFS_QGROUP_OPER_SUB_EXCL,
        BTRFS_QGROUP_OPER_SUB_SHARED,
+       BTRFS_QGROUP_OPER_SUB_SUBTREE,
 };
 
 struct btrfs_qgroup_operation {
index 4a88f073fdd79bf5440f2d54fb4771fc4361212c..0a6b6e4bcbb97a8af56ad6a58aef9f514c3b1132 100644 (file)
@@ -1416,7 +1416,8 @@ cleanup:
 
 static void async_rmw_stripe(struct btrfs_raid_bio *rbio)
 {
-       btrfs_init_work(&rbio->work, rmw_work, NULL, NULL);
+       btrfs_init_work(&rbio->work, btrfs_rmw_helper,
+                       rmw_work, NULL, NULL);
 
        btrfs_queue_work(rbio->fs_info->rmw_workers,
                         &rbio->work);
@@ -1424,7 +1425,8 @@ static void async_rmw_stripe(struct btrfs_raid_bio *rbio)
 
 static void async_read_rebuild(struct btrfs_raid_bio *rbio)
 {
-       btrfs_init_work(&rbio->work, read_rebuild_work, NULL, NULL);
+       btrfs_init_work(&rbio->work, btrfs_rmw_helper,
+                       read_rebuild_work, NULL, NULL);
 
        btrfs_queue_work(rbio->fs_info->rmw_workers,
                         &rbio->work);
@@ -1665,7 +1667,8 @@ static void btrfs_raid_unplug(struct blk_plug_cb *cb, bool from_schedule)
        plug = container_of(cb, struct btrfs_plug_cb, cb);
 
        if (from_schedule) {
-               btrfs_init_work(&plug->work, unplug_work, NULL, NULL);
+               btrfs_init_work(&plug->work, btrfs_rmw_helper,
+                               unplug_work, NULL, NULL);
                btrfs_queue_work(plug->info->rmw_workers,
                                 &plug->work);
                return;
index 09230cf3a2447b3541826f21b2f3fe1dcce202ce..20408c6b665ae94e03a152c94bb822bb87fdc63e 100644 (file)
@@ -798,7 +798,8 @@ static void reada_start_machine(struct btrfs_fs_info *fs_info)
                /* FIXME we cannot handle this properly right now */
                BUG();
        }
-       btrfs_init_work(&rmw->work, reada_start_machine_worker, NULL, NULL);
+       btrfs_init_work(&rmw->work, btrfs_readahead_helper,
+                       reada_start_machine_worker, NULL, NULL);
        rmw->fs_info = fs_info;
 
        btrfs_queue_work(fs_info->readahead_workers, &rmw->work);
index b6d198f5181ed6d07f8f9c29782bd5a99e46f9ce..f4a41f37be229b555fb2e26993aff7055ee7fff1 100644 (file)
@@ -428,8 +428,8 @@ struct scrub_ctx *scrub_setup_ctx(struct btrfs_device *dev, int is_dev_replace)
                sbio->index = i;
                sbio->sctx = sctx;
                sbio->page_count = 0;
-               btrfs_init_work(&sbio->work, scrub_bio_end_io_worker,
-                               NULL, NULL);
+               btrfs_init_work(&sbio->work, btrfs_scrub_helper,
+                               scrub_bio_end_io_worker, NULL, NULL);
 
                if (i != SCRUB_BIOS_PER_SCTX - 1)
                        sctx->bios[i]->next_free = i + 1;
@@ -999,8 +999,8 @@ nodatasum_case:
                fixup_nodatasum->root = fs_info->extent_root;
                fixup_nodatasum->mirror_num = failed_mirror_index + 1;
                scrub_pending_trans_workers_inc(sctx);
-               btrfs_init_work(&fixup_nodatasum->work, scrub_fixup_nodatasum,
-                               NULL, NULL);
+               btrfs_init_work(&fixup_nodatasum->work, btrfs_scrub_helper,
+                               scrub_fixup_nodatasum, NULL, NULL);
                btrfs_queue_work(fs_info->scrub_workers,
                                 &fixup_nodatasum->work);
                goto out;
@@ -1616,7 +1616,8 @@ static void scrub_wr_bio_end_io(struct bio *bio, int err)
        sbio->err = err;
        sbio->bio = bio;
 
-       btrfs_init_work(&sbio->work, scrub_wr_bio_end_io_worker, NULL, NULL);
+       btrfs_init_work(&sbio->work, btrfs_scrubwrc_helper,
+                        scrub_wr_bio_end_io_worker, NULL, NULL);
        btrfs_queue_work(fs_info->scrub_wr_completion_workers, &sbio->work);
 }
 
@@ -2904,6 +2905,7 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
        struct scrub_ctx *sctx;
        int ret;
        struct btrfs_device *dev;
+       struct rcu_string *name;
 
        if (btrfs_fs_closing(fs_info))
                return -EINVAL;
@@ -2965,6 +2967,16 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
                return -ENODEV;
        }
 
+       if (!is_dev_replace && !readonly && !dev->writeable) {
+               mutex_unlock(&fs_info->fs_devices->device_list_mutex);
+               rcu_read_lock();
+               name = rcu_dereference(dev->name);
+               btrfs_err(fs_info, "scrub: device %s is not writable",
+                         name->str);
+               rcu_read_unlock();
+               return -EROFS;
+       }
+
        mutex_lock(&fs_info->scrub_lock);
        if (!dev->in_fs_metadata || dev->is_tgtdev_for_dev_replace) {
                mutex_unlock(&fs_info->scrub_lock);
@@ -3203,7 +3215,8 @@ static int copy_nocow_pages(struct scrub_ctx *sctx, u64 logical, u64 len,
        nocow_ctx->len = len;
        nocow_ctx->mirror_num = mirror_num;
        nocow_ctx->physical_for_dev_replace = physical_for_dev_replace;
-       btrfs_init_work(&nocow_ctx->work, copy_nocow_pages_worker, NULL, NULL);
+       btrfs_init_work(&nocow_ctx->work, btrfs_scrubnc_helper,
+                       copy_nocow_pages_worker, NULL, NULL);
        INIT_LIST_HEAD(&nocow_ctx->inodes);
        btrfs_queue_work(fs_info->scrub_nocow_workers,
                         &nocow_ctx->work);
index 67b48b9a03e044eb2d83ab28447c8ead9db5192b..c4124de4435bffed06afc3a76ea6aba49a7c5317 100644 (file)
@@ -1665,6 +1665,21 @@ static int btrfs_calc_avail_data_space(struct btrfs_root *root, u64 *free_bytes)
        return 0;
 }
 
+/*
+ * Calculate numbers for 'df', pessimistic in case of mixed raid profiles.
+ *
+ * If there's a redundant raid level at DATA block groups, use the respective
+ * multiplier to scale the sizes.
+ *
+ * Unused device space usage is based on simulating the chunk allocator
+ * algorithm that respects the device sizes, order of allocations and the
+ * 'alloc_start' value, this is a close approximation of the actual use but
+ * there are other factors that may change the result (like a new metadata
+ * chunk).
+ *
+ * FIXME: not accurate for mixed block groups, total and free/used are ok,
+ * available appears slightly larger.
+ */
 static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct btrfs_fs_info *fs_info = btrfs_sb(dentry->d_sb);
@@ -1675,6 +1690,8 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
        u64 total_free_data = 0;
        int bits = dentry->d_sb->s_blocksize_bits;
        __be32 *fsid = (__be32 *)fs_info->fsid;
+       unsigned factor = 1;
+       struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv;
        int ret;
 
        /* holding chunk_muext to avoid allocating new chunks */
@@ -1682,30 +1699,52 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
        rcu_read_lock();
        list_for_each_entry_rcu(found, head, list) {
                if (found->flags & BTRFS_BLOCK_GROUP_DATA) {
+                       int i;
+
                        total_free_data += found->disk_total - found->disk_used;
                        total_free_data -=
                                btrfs_account_ro_block_groups_free_space(found);
+
+                       for (i = 0; i < BTRFS_NR_RAID_TYPES; i++) {
+                               if (!list_empty(&found->block_groups[i])) {
+                                       switch (i) {
+                                       case BTRFS_RAID_DUP:
+                                       case BTRFS_RAID_RAID1:
+                                       case BTRFS_RAID_RAID10:
+                                               factor = 2;
+                                       }
+                               }
+                       }
                }
 
                total_used += found->disk_used;
        }
+
        rcu_read_unlock();
 
-       buf->f_namelen = BTRFS_NAME_LEN;
-       buf->f_blocks = btrfs_super_total_bytes(disk_super) >> bits;
-       buf->f_bfree = buf->f_blocks - (total_used >> bits);
-       buf->f_bsize = dentry->d_sb->s_blocksize;
-       buf->f_type = BTRFS_SUPER_MAGIC;
+       buf->f_blocks = div_u64(btrfs_super_total_bytes(disk_super), factor);
+       buf->f_blocks >>= bits;
+       buf->f_bfree = buf->f_blocks - (div_u64(total_used, factor) >> bits);
+
+       /* Account global block reserve as used, it's in logical size already */
+       spin_lock(&block_rsv->lock);
+       buf->f_bfree -= block_rsv->size >> bits;
+       spin_unlock(&block_rsv->lock);
+
        buf->f_bavail = total_free_data;
        ret = btrfs_calc_avail_data_space(fs_info->tree_root, &total_free_data);
        if (ret) {
                mutex_unlock(&fs_info->chunk_mutex);
                return ret;
        }
-       buf->f_bavail += total_free_data;
+       buf->f_bavail += div_u64(total_free_data, factor);
        buf->f_bavail = buf->f_bavail >> bits;
        mutex_unlock(&fs_info->chunk_mutex);
 
+       buf->f_type = BTRFS_SUPER_MAGIC;
+       buf->f_bsize = dentry->d_sb->s_blocksize;
+       buf->f_namelen = BTRFS_NAME_LEN;
+
        /* We treat it as constant endianness (it doesn't matter _which_)
           because we want the fsid to come out the same whether mounted
           on a big-endian or little-endian host */
index 78699364f537c423b9fa25cb0e3c124ded8c6ce7..12e53556e214c2c26f0a67aadf63b53637178822 100644 (file)
@@ -614,7 +614,7 @@ int btrfs_kobj_rm_device(struct btrfs_fs_info *fs_info,
        if (!fs_info->device_dir_kobj)
                return -EINVAL;
 
-       if (one_device) {
+       if (one_device && one_device->bdev) {
                disk = one_device->bdev->bd_part;
                disk_kobj = &part_to_dev(disk)->kobj;
 
index 5f379affdf236119f4ab031ad6843a822a0ec24c..d89c6d3542cab4c55372954ae97e9e32ec1ba443 100644 (file)
@@ -218,7 +218,6 @@ loop:
        spin_lock_init(&cur_trans->delayed_refs.lock);
 
        INIT_LIST_HEAD(&cur_trans->pending_snapshots);
-       INIT_LIST_HEAD(&cur_trans->ordered_operations);
        INIT_LIST_HEAD(&cur_trans->pending_chunks);
        INIT_LIST_HEAD(&cur_trans->switch_commits);
        list_add_tail(&cur_trans->list, &fs_info->trans_list);
@@ -1612,27 +1611,6 @@ static void cleanup_transaction(struct btrfs_trans_handle *trans,
        kmem_cache_free(btrfs_trans_handle_cachep, trans);
 }
 
-static int btrfs_flush_all_pending_stuffs(struct btrfs_trans_handle *trans,
-                                         struct btrfs_root *root)
-{
-       int ret;
-
-       ret = btrfs_run_delayed_items(trans, root);
-       if (ret)
-               return ret;
-
-       /*
-        * rename don't use btrfs_join_transaction, so, once we
-        * set the transaction to blocked above, we aren't going
-        * to get any new ordered operations.  We can safely run
-        * it here and no for sure that nothing new will be added
-        * to the list
-        */
-       ret = btrfs_run_ordered_operations(trans, root, 1);
-
-       return ret;
-}
-
 static inline int btrfs_start_delalloc_flush(struct btrfs_fs_info *fs_info)
 {
        if (btrfs_test_opt(fs_info->tree_root, FLUSHONCOMMIT))
@@ -1653,13 +1631,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
        struct btrfs_transaction *prev_trans = NULL;
        int ret;
 
-       ret = btrfs_run_ordered_operations(trans, root, 0);
-       if (ret) {
-               btrfs_abort_transaction(trans, root, ret);
-               btrfs_end_transaction(trans, root);
-               return ret;
-       }
-
        /* Stop the commit early if ->aborted is set */
        if (unlikely(ACCESS_ONCE(cur_trans->aborted))) {
                ret = cur_trans->aborted;
@@ -1740,7 +1711,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
        if (ret)
                goto cleanup_transaction;
 
-       ret = btrfs_flush_all_pending_stuffs(trans, root);
+       ret = btrfs_run_delayed_items(trans, root);
        if (ret)
                goto cleanup_transaction;
 
@@ -1748,7 +1719,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
                   extwriter_counter_read(cur_trans) == 0);
 
        /* some pending stuffs might be added after the previous flush. */
-       ret = btrfs_flush_all_pending_stuffs(trans, root);
+       ret = btrfs_run_delayed_items(trans, root);
        if (ret)
                goto cleanup_transaction;
 
index 7dd558ed0716526fa5700c179d2f0606b8a53219..579be51b27e5ee0970feb4fb21ddf54a1d621a12 100644 (file)
@@ -55,7 +55,6 @@ struct btrfs_transaction {
        wait_queue_head_t writer_wait;
        wait_queue_head_t commit_wait;
        struct list_head pending_snapshots;
-       struct list_head ordered_operations;
        struct list_head pending_chunks;
        struct list_head switch_commits;
        struct btrfs_delayed_ref_root delayed_refs;
index 9e1f2cd5e67ab0fff18ec12df76c965e109e662c..7e0e6e3029dd4e36e9fd72e68b151ac991b66c12 100644 (file)
@@ -3298,7 +3298,7 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
        struct list_head ordered_sums;
        int skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM;
        bool has_extents = false;
-       bool need_find_last_extent = (*last_extent == 0);
+       bool need_find_last_extent = true;
        bool done = false;
 
        INIT_LIST_HEAD(&ordered_sums);
@@ -3352,8 +3352,7 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
                 */
                if (ins_keys[i].type == BTRFS_EXTENT_DATA_KEY) {
                        has_extents = true;
-                       if (need_find_last_extent &&
-                           first_key.objectid == (u64)-1)
+                       if (first_key.objectid == (u64)-1)
                                first_key = ins_keys[i];
                } else {
                        need_find_last_extent = false;
@@ -3427,6 +3426,16 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
        if (!has_extents)
                return ret;
 
+       if (need_find_last_extent && *last_extent == first_key.offset) {
+               /*
+                * We don't have any leafs between our current one and the one
+                * we processed before that can have file extent items for our
+                * inode (and have a generation number smaller than our current
+                * transaction id).
+                */
+               need_find_last_extent = false;
+       }
+
        /*
         * Because we use btrfs_search_forward we could skip leaves that were
         * not modified and then assume *last_extent is valid when it really
@@ -3537,7 +3546,7 @@ fill_holes:
                                               0, 0);
                if (ret)
                        break;
-               *last_extent = offset + len;
+               *last_extent = extent_end;
        }
        /*
         * Need to let the callers know we dropped the path so they should
index 7f78cbf5cf413636e7b6072efca05110dce8b211..4c29db604bbe135fb1bdb3743c7eee408499d25c 100644 (file)
@@ -57,6 +57,21 @@ void ulist_free(struct ulist *ulist);
 int ulist_add(struct ulist *ulist, u64 val, u64 aux, gfp_t gfp_mask);
 int ulist_add_merge(struct ulist *ulist, u64 val, u64 aux,
                    u64 *old_aux, gfp_t gfp_mask);
+
+/* just like ulist_add_merge() but take a pointer for the aux data */
+static inline int ulist_add_merge_ptr(struct ulist *ulist, u64 val, void *aux,
+                                     void **old_aux, gfp_t gfp_mask)
+{
+#if BITS_PER_LONG == 32
+       u64 old64 = (uintptr_t)*old_aux;
+       int ret = ulist_add_merge(ulist, val, (uintptr_t)aux, &old64, gfp_mask);
+       *old_aux = (void *)((uintptr_t)old64);
+       return ret;
+#else
+       return ulist_add_merge(ulist, val, (u64)aux, (u64 *)old_aux, gfp_mask);
+#endif
+}
+
 struct ulist_node *ulist_next(struct ulist *ulist,
                              struct ulist_iterator *uiter);
 
index 6cb82f62cb7c22c4b3038e248e52b9694171a5bd..340a92d08e84d9e5268a18fe5f3112465fa47888 100644 (file)
@@ -508,6 +508,44 @@ static noinline int device_list_add(const char *path,
                ret = 1;
                device->fs_devices = fs_devices;
        } else if (!device->name || strcmp(device->name->str, path)) {
+               /*
+                * When FS is already mounted.
+                * 1. If you are here and if the device->name is NULL that
+                *    means this device was missing at time of FS mount.
+                * 2. If you are here and if the device->name is different
+                *    from 'path' that means either
+                *      a. The same device disappeared and reappeared with
+                *         different name. or
+                *      b. The missing-disk-which-was-replaced, has
+                *         reappeared now.
+                *
+                * We must allow 1 and 2a above. But 2b would be a spurious
+                * and unintentional.
+                *
+                * Further in case of 1 and 2a above, the disk at 'path'
+                * would have missed some transaction when it was away and
+                * in case of 2a the stale bdev has to be updated as well.
+                * 2b must not be allowed at all time.
+                */
+
+               /*
+                * As of now don't allow update to btrfs_fs_device through
+                * the btrfs dev scan cli, after FS has been mounted.
+                */
+               if (fs_devices->opened) {
+                       return -EBUSY;
+               } else {
+                       /*
+                        * That is if the FS is _not_ mounted and if you
+                        * are here, that means there is more than one
+                        * disk with same uuid and devid.We keep the one
+                        * with larger generation number or the last-in if
+                        * generation are equal.
+                        */
+                       if (found_transid < device->generation)
+                               return -EEXIST;
+               }
+
                name = rcu_string_strdup(path, GFP_NOFS);
                if (!name)
                        return -ENOMEM;
@@ -519,6 +557,15 @@ static noinline int device_list_add(const char *path,
                }
        }
 
+       /*
+        * Unmount does not free the btrfs_device struct but would zero
+        * generation along with most of the other members. So just update
+        * it back. We need it to pick the disk with largest generation
+        * (as above).
+        */
+       if (!fs_devices->opened)
+               device->generation = found_transid;
+
        if (found_transid > fs_devices->latest_trans) {
                fs_devices->latest_devid = devid;
                fs_devices->latest_trans = found_transid;
@@ -1436,7 +1483,7 @@ static int btrfs_add_device(struct btrfs_trans_handle *trans,
        btrfs_set_device_io_align(leaf, dev_item, device->io_align);
        btrfs_set_device_io_width(leaf, dev_item, device->io_width);
        btrfs_set_device_sector_size(leaf, dev_item, device->sector_size);
-       btrfs_set_device_total_bytes(leaf, dev_item, device->total_bytes);
+       btrfs_set_device_total_bytes(leaf, dev_item, device->disk_total_bytes);
        btrfs_set_device_bytes_used(leaf, dev_item, device->bytes_used);
        btrfs_set_device_group(leaf, dev_item, 0);
        btrfs_set_device_seek_speed(leaf, dev_item, 0);
@@ -1671,7 +1718,7 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
        device->fs_devices->total_devices--;
 
        if (device->missing)
-               root->fs_info->fs_devices->missing_devices--;
+               device->fs_devices->missing_devices--;
 
        next_device = list_entry(root->fs_info->fs_devices->devices.next,
                                 struct btrfs_device, dev_list);
@@ -1801,8 +1848,12 @@ void btrfs_rm_dev_replace_srcdev(struct btrfs_fs_info *fs_info,
        if (srcdev->bdev) {
                fs_info->fs_devices->open_devices--;
 
-               /* zero out the old super */
-               btrfs_scratch_superblock(srcdev);
+               /*
+                * zero out the old super if it is not writable
+                * (e.g. seed device)
+                */
+               if (srcdev->writeable)
+                       btrfs_scratch_superblock(srcdev);
        }
 
        call_rcu(&srcdev->rcu, free_device);
@@ -1941,6 +1992,9 @@ static int btrfs_prepare_sprout(struct btrfs_root *root)
        fs_devices->seeding = 0;
        fs_devices->num_devices = 0;
        fs_devices->open_devices = 0;
+       fs_devices->missing_devices = 0;
+       fs_devices->num_can_discard = 0;
+       fs_devices->rotating = 0;
        fs_devices->seed = seed_devices;
 
        generate_random_uuid(fs_devices->fsid);
@@ -5800,7 +5854,8 @@ struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info,
        else
                generate_random_uuid(dev->uuid);
 
-       btrfs_init_work(&dev->work, pending_bios_fn, NULL, NULL);
+       btrfs_init_work(&dev->work, btrfs_submit_helper,
+                       pending_bios_fn, NULL, NULL);
 
        return dev;
 }
index ac4f260155c875b80d9d6611af1139438e62fc91..889b9845575079517e92ee387fe5c863751c3848 100644 (file)
@@ -207,6 +207,19 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
        return 0;
 }
 
+static long cifs_fallocate(struct file *file, int mode, loff_t off, loff_t len)
+{
+       struct super_block *sb = file->f_path.dentry->d_sb;
+       struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
+       struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
+       struct TCP_Server_Info *server = tcon->ses->server;
+
+       if (server->ops->fallocate)
+               return server->ops->fallocate(file, tcon, mode, off, len);
+
+       return -EOPNOTSUPP;
+}
+
 static int cifs_permission(struct inode *inode, int mask)
 {
        struct cifs_sb_info *cifs_sb;
@@ -812,8 +825,9 @@ static int cifs_setlease(struct file *file, long arg, struct file_lock **lease)
        if (!(S_ISREG(inode->i_mode)))
                return -EINVAL;
 
-       /* check if file is oplocked */
-       if (((arg == F_RDLCK) && CIFS_CACHE_READ(CIFS_I(inode))) ||
+       /* Check if file is oplocked if this is request for new lease */
+       if (arg == F_UNLCK ||
+           ((arg == F_RDLCK) && CIFS_CACHE_READ(CIFS_I(inode))) ||
            ((arg == F_WRLCK) && CIFS_CACHE_WRITE(CIFS_I(inode))))
                return generic_setlease(file, arg, lease);
        else if (tlink_tcon(cfile->tlink)->local_lease &&
@@ -908,6 +922,7 @@ const struct file_operations cifs_file_ops = {
        .unlocked_ioctl = cifs_ioctl,
 #endif /* CONFIG_CIFS_POSIX */
        .setlease = cifs_setlease,
+       .fallocate = cifs_fallocate,
 };
 
 const struct file_operations cifs_file_strict_ops = {
@@ -927,6 +942,7 @@ const struct file_operations cifs_file_strict_ops = {
        .unlocked_ioctl = cifs_ioctl,
 #endif /* CONFIG_CIFS_POSIX */
        .setlease = cifs_setlease,
+       .fallocate = cifs_fallocate,
 };
 
 const struct file_operations cifs_file_direct_ops = {
@@ -947,6 +963,7 @@ const struct file_operations cifs_file_direct_ops = {
 #endif /* CONFIG_CIFS_POSIX */
        .llseek = cifs_llseek,
        .setlease = cifs_setlease,
+       .fallocate = cifs_fallocate,
 };
 
 const struct file_operations cifs_file_nobrl_ops = {
@@ -965,6 +982,7 @@ const struct file_operations cifs_file_nobrl_ops = {
        .unlocked_ioctl = cifs_ioctl,
 #endif /* CONFIG_CIFS_POSIX */
        .setlease = cifs_setlease,
+       .fallocate = cifs_fallocate,
 };
 
 const struct file_operations cifs_file_strict_nobrl_ops = {
@@ -983,6 +1001,7 @@ const struct file_operations cifs_file_strict_nobrl_ops = {
        .unlocked_ioctl = cifs_ioctl,
 #endif /* CONFIG_CIFS_POSIX */
        .setlease = cifs_setlease,
+       .fallocate = cifs_fallocate,
 };
 
 const struct file_operations cifs_file_direct_nobrl_ops = {
@@ -1002,6 +1021,7 @@ const struct file_operations cifs_file_direct_nobrl_ops = {
 #endif /* CONFIG_CIFS_POSIX */
        .llseek = cifs_llseek,
        .setlease = cifs_setlease,
+       .fallocate = cifs_fallocate,
 };
 
 const struct file_operations cifs_dir_ops = {
index 0012e1e291d427cbb4a6696792cb85743231ec1e..dfc731b02aa9b3daca3a15d95346bcd82cc2b3d5 100644 (file)
@@ -409,6 +409,10 @@ struct smb_version_operations {
        /* get mtu credits */
        int (*wait_mtu_credits)(struct TCP_Server_Info *, unsigned int,
                                unsigned int *, unsigned int *);
+       /* check if we need to issue closedir */
+       bool (*dir_needs_close)(struct cifsFileInfo *);
+       long (*fallocate)(struct file *, struct cifs_tcon *, int, loff_t,
+                         loff_t);
 };
 
 struct smb_version_values {
@@ -883,6 +887,7 @@ struct cifs_tcon {
                                for this mount even if server would support */
        bool local_lease:1; /* check leases (only) on local system not remote */
        bool broken_posix_open; /* e.g. Samba server versions < 3.3.2, 3.2.9 */
+       bool broken_sparse_sup; /* if server or share does not support sparse */
        bool need_reconnect:1; /* connection reset, tid now invalid */
 #ifdef CONFIG_CIFS_SMB2
        bool print:1;           /* set if connection to printer share */
index 33df36ef9d52037e69857f1dc7b1c9591acb8251..5f9822ac0245dcd637838b3fda843b3cc4d09901 100644 (file)
@@ -2253,6 +2253,29 @@ typedef struct {
 /* minimum includes first three fields, and empty FS Name */
 #define MIN_FS_ATTR_INFO_SIZE 12
 
+
+/* List of FileSystemAttributes - see 2.5.1 of MS-FSCC */
+#define FILE_SUPPORT_INTEGRITY_STREAMS 0x04000000
+#define FILE_SUPPORTS_USN_JOURNAL      0x02000000
+#define FILE_SUPPORTS_OPEN_BY_FILE_ID  0x01000000
+#define FILE_SUPPORTS_EXTENDED_ATTRIBUTES 0x00800000
+#define FILE_SUPPORTS_HARD_LINKS       0x00400000
+#define FILE_SUPPORTS_TRANSACTIONS     0x00200000
+#define FILE_SEQUENTIAL_WRITE_ONCE     0x00100000
+#define FILE_READ_ONLY_VOLUME          0x00080000
+#define FILE_NAMED_STREAMS             0x00040000
+#define FILE_SUPPORTS_ENCRYPTION       0x00020000
+#define FILE_SUPPORTS_OBJECT_IDS       0x00010000
+#define FILE_VOLUME_IS_COMPRESSED      0x00008000
+#define FILE_SUPPORTS_REMOTE_STORAGE   0x00000100
+#define FILE_SUPPORTS_REPARSE_POINTS   0x00000080
+#define FILE_SUPPORTS_SPARSE_FILES     0x00000040
+#define FILE_VOLUME_QUOTAS             0x00000020
+#define FILE_FILE_COMPRESSION          0x00000010
+#define FILE_PERSISTENT_ACLS           0x00000008
+#define FILE_UNICODE_ON_DISK           0x00000004
+#define FILE_CASE_PRESERVED_NAMES      0x00000002
+#define FILE_CASE_SENSITIVE_SEARCH     0x00000001
 typedef struct {
        __le32 Attributes;
        __le32 MaxPathNameComponentLength;
index 4ab2f79ffa7a4eb7f2e6ac3a2a8d67131d8f8080..d5fec92e036068b98bf2e3426e3f8d159b70e048 100644 (file)
@@ -762,7 +762,7 @@ int cifs_closedir(struct inode *inode, struct file *file)
 
        cifs_dbg(FYI, "Freeing private data in close dir\n");
        spin_lock(&cifs_file_list_lock);
-       if (!cfile->srch_inf.endOfSearch && !cfile->invalidHandle) {
+       if (server->ops->dir_needs_close(cfile)) {
                cfile->invalidHandle = true;
                spin_unlock(&cifs_file_list_lock);
                if (server->ops->close_dir)
index 426d6c6ad8bfacfa188f2eb2dfb5385620559f44..949ec909ec9ab94747ed332cc96cdcdbc29fd47b 100644 (file)
@@ -1727,6 +1727,12 @@ unlink_target:
                                    target_dentry, to_name);
        }
 
+       /* force revalidate to go get info when needed */
+       CIFS_I(source_dir)->time = CIFS_I(target_dir)->time = 0;
+
+       source_dir->i_ctime = source_dir->i_mtime = target_dir->i_ctime =
+               target_dir->i_mtime = current_fs_time(source_dir->i_sb);
+
 cifs_rename_exit:
        kfree(info_buf_source);
        kfree(from_name);
index 81340c6253eb36bcaf922c8e1b955e5d493099ca..b7415d596dbd478926d75cdaca022ac8960a65c3 100644 (file)
@@ -574,13 +574,6 @@ void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock)
                cinode->oplock = 0;
 }
 
-static int
-cifs_oplock_break_wait(void *unused)
-{
-       schedule();
-       return signal_pending(current) ? -ERESTARTSYS : 0;
-}
-
 /*
  * We wait for oplock breaks to be processed before we attempt to perform
  * writes.
index b15862e0f68c3c749a7cf6278dc6d3666ba71ccc..798c80a41c886b3fba7e66f8264066902d35b8cb 100644 (file)
@@ -593,7 +593,7 @@ find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos,
                /* close and restart search */
                cifs_dbg(FYI, "search backing up - close and restart search\n");
                spin_lock(&cifs_file_list_lock);
-               if (!cfile->srch_inf.endOfSearch && !cfile->invalidHandle) {
+               if (server->ops->dir_needs_close(cfile)) {
                        cfile->invalidHandle = true;
                        spin_unlock(&cifs_file_list_lock);
                        if (server->ops->close)
index 5e8c22d6c7b9dc96f4079a9579fd8b5c68143af8..1a6df4b03f67cae97688d7a9578d7317a88419bf 100644 (file)
@@ -1015,6 +1015,12 @@ cifs_wp_retry_size(struct inode *inode)
        return CIFS_SB(inode->i_sb)->wsize;
 }
 
+static bool
+cifs_dir_needs_close(struct cifsFileInfo *cfile)
+{
+       return !cfile->srch_inf.endOfSearch && !cfile->invalidHandle;
+}
+
 struct smb_version_operations smb1_operations = {
        .send_cancel = send_nt_cancel,
        .compare_fids = cifs_compare_fids,
@@ -1086,6 +1092,7 @@ struct smb_version_operations smb1_operations = {
        .create_mf_symlink = cifs_create_mf_symlink,
        .is_read_op = cifs_is_read_op,
        .wp_retry_size = cifs_wp_retry_size,
+       .dir_needs_close = cifs_dir_needs_close,
 #ifdef CONFIG_CIFS_XATTR
        .query_all_EAs = CIFSSMBQAllEAs,
        .set_EA = CIFSSMBSetEA,
index e31a9dfdcd39a8cf7a68d18a45922f9001b918d6..af59d03db49280488a33abe5ec372599aa8ad4ed 100644 (file)
@@ -214,7 +214,7 @@ static const struct status_to_posix_error smb2_error_map_table[] = {
        {STATUS_BREAKPOINT, -EIO, "STATUS_BREAKPOINT"},
        {STATUS_SINGLE_STEP, -EIO, "STATUS_SINGLE_STEP"},
        {STATUS_BUFFER_OVERFLOW, -EIO, "STATUS_BUFFER_OVERFLOW"},
-       {STATUS_NO_MORE_FILES, -EIO, "STATUS_NO_MORE_FILES"},
+       {STATUS_NO_MORE_FILES, -ENODATA, "STATUS_NO_MORE_FILES"},
        {STATUS_WAKE_SYSTEM_DEBUGGER, -EIO, "STATUS_WAKE_SYSTEM_DEBUGGER"},
        {STATUS_HANDLES_CLOSED, -EIO, "STATUS_HANDLES_CLOSED"},
        {STATUS_NO_INHERITANCE, -EIO, "STATUS_NO_INHERITANCE"},
@@ -298,7 +298,7 @@ static const struct status_to_posix_error smb2_error_map_table[] = {
        {STATUS_INVALID_PARAMETER, -EINVAL, "STATUS_INVALID_PARAMETER"},
        {STATUS_NO_SUCH_DEVICE, -ENODEV, "STATUS_NO_SUCH_DEVICE"},
        {STATUS_NO_SUCH_FILE, -ENOENT, "STATUS_NO_SUCH_FILE"},
-       {STATUS_INVALID_DEVICE_REQUEST, -EIO, "STATUS_INVALID_DEVICE_REQUEST"},
+       {STATUS_INVALID_DEVICE_REQUEST, -EOPNOTSUPP, "STATUS_INVALID_DEVICE_REQUEST"},
        {STATUS_END_OF_FILE, -ENODATA, "STATUS_END_OF_FILE"},
        {STATUS_WRONG_VOLUME, -EIO, "STATUS_WRONG_VOLUME"},
        {STATUS_NO_MEDIA_IN_DEVICE, -EIO, "STATUS_NO_MEDIA_IN_DEVICE"},
index f2e6ac29a8d661b82f4ba1712dee36a842d6f7cd..4aa7a0f07d6eace61da47500bb6e83a5bd39e294 100644 (file)
@@ -178,9 +178,24 @@ smb2_check_message(char *buf, unsigned int length)
                /* Windows 7 server returns 24 bytes more */
                if (clc_len + 20 == len && command == SMB2_OPLOCK_BREAK_HE)
                        return 0;
-               /* server can return one byte more */
+               /* server can return one byte more due to implied bcc[0] */
                if (clc_len == 4 + len + 1)
                        return 0;
+
+               /*
+                * MacOS server pads after SMB2.1 write response with 3 bytes
+                * of junk. Other servers match RFC1001 len to actual
+                * SMB2/SMB3 frame length (header + smb2 response specific data)
+                * Log the server error (once), but allow it and continue
+                * since the frame is parseable.
+                */
+               if (clc_len < 4 /* RFC1001 header size */ + len) {
+                       printk_once(KERN_WARNING
+                               "SMB2 server sent bad RFC1001 len %d not %d\n",
+                               len, clc_len - 4);
+                       return 0;
+               }
+
                return 1;
        }
        return 0;
index 77f8aeb9c2fc7ecb9a2c45785a65d6e9a45700fa..5a48aa290dfe83fdab6f9af322aadcdd0ebe3b3b 100644 (file)
@@ -731,11 +731,72 @@ smb2_sync_write(const unsigned int xid, struct cifsFileInfo *cfile,
        return SMB2_write(xid, parms, written, iov, nr_segs);
 }
 
+/* Set or clear the SPARSE_FILE attribute based on value passed in setsparse */
+static bool smb2_set_sparse(const unsigned int xid, struct cifs_tcon *tcon,
+               struct cifsFileInfo *cfile, struct inode *inode, __u8 setsparse)
+{
+       struct cifsInodeInfo *cifsi;
+       int rc;
+
+       cifsi = CIFS_I(inode);
+
+       /* if file already sparse don't bother setting sparse again */
+       if ((cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE) && setsparse)
+               return true; /* already sparse */
+
+       if (!(cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE) && !setsparse)
+               return true; /* already not sparse */
+
+       /*
+        * Can't check for sparse support on share the usual way via the
+        * FS attribute info (FILE_SUPPORTS_SPARSE_FILES) on the share
+        * since Samba server doesn't set the flag on the share, yet
+        * supports the set sparse FSCTL and returns sparse correctly
+        * in the file attributes. If we fail setting sparse though we
+        * mark that server does not support sparse files for this share
+        * to avoid repeatedly sending the unsupported fsctl to server
+        * if the file is repeatedly extended.
+        */
+       if (tcon->broken_sparse_sup)
+               return false;
+
+       rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
+                       cfile->fid.volatile_fid, FSCTL_SET_SPARSE,
+                       true /* is_fctl */, &setsparse, 1, NULL, NULL);
+       if (rc) {
+               tcon->broken_sparse_sup = true;
+               cifs_dbg(FYI, "set sparse rc = %d\n", rc);
+               return false;
+       }
+
+       if (setsparse)
+               cifsi->cifsAttrs |= FILE_ATTRIBUTE_SPARSE_FILE;
+       else
+               cifsi->cifsAttrs &= (~FILE_ATTRIBUTE_SPARSE_FILE);
+
+       return true;
+}
+
 static int
 smb2_set_file_size(const unsigned int xid, struct cifs_tcon *tcon,
                   struct cifsFileInfo *cfile, __u64 size, bool set_alloc)
 {
        __le64 eof = cpu_to_le64(size);
+       struct inode *inode;
+
+       /*
+        * If extending file more than one page make sparse. Many Linux fs
+        * make files sparse by default when extending via ftruncate
+        */
+       inode = cfile->dentry->d_inode;
+
+       if (!set_alloc && (size > inode->i_size + 8192)) {
+               __u8 set_sparse = 1;
+
+               /* whether set sparse succeeds or not, extend the file */
+               smb2_set_sparse(xid, tcon, cfile, inode, set_sparse);
+       }
+
        return SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid,
                            cfile->fid.volatile_fid, cfile->pid, &eof, false);
 }
@@ -954,6 +1015,105 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
        return rc;
 }
 
+static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
+                           loff_t offset, loff_t len, bool keep_size)
+{
+       struct inode *inode;
+       struct cifsInodeInfo *cifsi;
+       struct cifsFileInfo *cfile = file->private_data;
+       struct file_zero_data_information fsctl_buf;
+       long rc;
+       unsigned int xid;
+
+       xid = get_xid();
+
+       inode = cfile->dentry->d_inode;
+       cifsi = CIFS_I(inode);
+
+       /* if file not oplocked can't be sure whether asking to extend size */
+       if (!CIFS_CACHE_READ(cifsi))
+               if (keep_size == false)
+                       return -EOPNOTSUPP;
+
+       /* 
+        * Must check if file sparse since fallocate -z (zero range) assumes
+        * non-sparse allocation
+        */
+       if (!(cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE))
+               return -EOPNOTSUPP;
+
+       /*
+        * need to make sure we are not asked to extend the file since the SMB3
+        * fsctl does not change the file size. In the future we could change
+        * this to zero the first part of the range then set the file size
+        * which for a non sparse file would zero the newly extended range
+        */
+       if (keep_size == false)
+               if (i_size_read(inode) < offset + len)
+                       return -EOPNOTSUPP;
+
+       cifs_dbg(FYI, "offset %lld len %lld", offset, len);
+
+       fsctl_buf.FileOffset = cpu_to_le64(offset);
+       fsctl_buf.BeyondFinalZero = cpu_to_le64(offset + len);
+
+       rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
+                       cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA,
+                       true /* is_fctl */, (char *)&fsctl_buf,
+                       sizeof(struct file_zero_data_information), NULL, NULL);
+       free_xid(xid);
+       return rc;
+}
+
+static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
+                           loff_t offset, loff_t len)
+{
+       struct inode *inode;
+       struct cifsInodeInfo *cifsi;
+       struct cifsFileInfo *cfile = file->private_data;
+       struct file_zero_data_information fsctl_buf;
+       long rc;
+       unsigned int xid;
+       __u8 set_sparse = 1;
+
+       xid = get_xid();
+
+       inode = cfile->dentry->d_inode;
+       cifsi = CIFS_I(inode);
+
+       /* Need to make file sparse, if not already, before freeing range. */
+       /* Consider adding equivalent for compressed since it could also work */
+       if (!smb2_set_sparse(xid, tcon, cfile, inode, set_sparse))
+               return -EOPNOTSUPP;
+
+       cifs_dbg(FYI, "offset %lld len %lld", offset, len);
+
+       fsctl_buf.FileOffset = cpu_to_le64(offset);
+       fsctl_buf.BeyondFinalZero = cpu_to_le64(offset + len);
+
+       rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
+                       cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA,
+                       true /* is_fctl */, (char *)&fsctl_buf,
+                       sizeof(struct file_zero_data_information), NULL, NULL);
+       free_xid(xid);
+       return rc;
+}
+
+static long smb3_fallocate(struct file *file, struct cifs_tcon *tcon, int mode,
+                          loff_t off, loff_t len)
+{
+       /* KEEP_SIZE already checked for by do_fallocate */
+       if (mode & FALLOC_FL_PUNCH_HOLE)
+               return smb3_punch_hole(file, tcon, off, len);
+       else if (mode & FALLOC_FL_ZERO_RANGE) {
+               if (mode & FALLOC_FL_KEEP_SIZE)
+                       return smb3_zero_range(file, tcon, off, len, true);
+               return smb3_zero_range(file, tcon, off, len, false);
+       }
+
+       return -EOPNOTSUPP;
+}
+
 static void
 smb2_downgrade_oplock(struct TCP_Server_Info *server,
                        struct cifsInodeInfo *cinode, bool set_level2)
@@ -1161,6 +1321,12 @@ smb2_wp_retry_size(struct inode *inode)
                     SMB2_MAX_BUFFER_SIZE);
 }
 
+static bool
+smb2_dir_needs_close(struct cifsFileInfo *cfile)
+{
+       return !cfile->invalidHandle;
+}
+
 struct smb_version_operations smb20_operations = {
        .compare_fids = smb2_compare_fids,
        .setup_request = smb2_setup_request,
@@ -1236,6 +1402,7 @@ struct smb_version_operations smb20_operations = {
        .parse_lease_buf = smb2_parse_lease_buf,
        .clone_range = smb2_clone_range,
        .wp_retry_size = smb2_wp_retry_size,
+       .dir_needs_close = smb2_dir_needs_close,
 };
 
 struct smb_version_operations smb21_operations = {
@@ -1313,6 +1480,7 @@ struct smb_version_operations smb21_operations = {
        .parse_lease_buf = smb2_parse_lease_buf,
        .clone_range = smb2_clone_range,
        .wp_retry_size = smb2_wp_retry_size,
+       .dir_needs_close = smb2_dir_needs_close,
 };
 
 struct smb_version_operations smb30_operations = {
@@ -1393,6 +1561,8 @@ struct smb_version_operations smb30_operations = {
        .clone_range = smb2_clone_range,
        .validate_negotiate = smb3_validate_negotiate,
        .wp_retry_size = smb2_wp_retry_size,
+       .dir_needs_close = smb2_dir_needs_close,
+       .fallocate = smb3_fallocate,
 };
 
 struct smb_version_values smb20_values = {
index 42ebc1a8be6cb241c5ee77e1944f063ae15a472d..fa0dd044213b9dc7dab5ec26d37c469627e9ca49 100644 (file)
@@ -907,7 +907,8 @@ tcon_exit:
 tcon_error_exit:
        if (rsp->hdr.Status == STATUS_BAD_NETWORK_NAME) {
                cifs_dbg(VFS, "BAD_NETWORK_NAME: %s\n", tree);
-               tcon->bad_network_name = true;
+               if (tcon)
+                       tcon->bad_network_name = true;
        }
        goto tcon_exit;
 }
@@ -1224,7 +1225,9 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
 
        cifs_dbg(FYI, "SMB2 IOCTL\n");
 
-       *out_data = NULL;
+       if (out_data != NULL)
+               *out_data = NULL;
+
        /* zero out returned data len, in case of error */
        if (plen)
                *plen = 0;
@@ -2177,6 +2180,10 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
        rsp = (struct smb2_query_directory_rsp *)iov[0].iov_base;
 
        if (rc) {
+               if (rc == -ENODATA && rsp->hdr.Status == STATUS_NO_MORE_FILES) {
+                       srch_inf->endOfSearch = true;
+                       rc = 0;
+               }
                cifs_stats_fail_inc(tcon, SMB2_QUERY_DIRECTORY_HE);
                goto qdir_exit;
        }
@@ -2214,11 +2221,6 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
        else
                cifs_dbg(VFS, "illegal search buffer type\n");
 
-       if (rsp->hdr.Status == STATUS_NO_MORE_FILES)
-               srch_inf->endOfSearch = 1;
-       else
-               srch_inf->endOfSearch = 0;
-
        return rc;
 
 qdir_exit:
index 69f3595d3952b74a595650103a791aec839f69a5..fbe486c285a90aff757a43569330fb32c9bbb50d 100644 (file)
@@ -573,6 +573,12 @@ struct copychunk_ioctl {
        __u32 Reserved2;
 } __packed;
 
+/* this goes in the ioctl buffer when doing FSCTL_SET_ZERO_DATA */
+struct file_zero_data_information {
+       __le64  FileOffset;
+       __le64  BeyondFinalZero;
+} __packed;
+
 struct copychunk_ioctl_rsp {
        __le32 ChunksWritten;
        __le32 ChunkBytesWritten;
index 0e538b5c96221f61f55f9a8bff58d6d88cfc836b..83efa59535bedf988292548c0fcba1526fcdde1c 100644 (file)
@@ -63,7 +63,7 @@
 #define FSCTL_SET_OBJECT_ID_EXTENDED 0x000900BC /* BB add struct */
 #define FSCTL_CREATE_OR_GET_OBJECT_ID 0x000900C0 /* BB add struct */
 #define FSCTL_SET_SPARSE             0x000900C4 /* BB add struct */
-#define FSCTL_SET_ZERO_DATA          0x000900C8 /* BB add struct */
+#define FSCTL_SET_ZERO_DATA          0x000980C8
 #define FSCTL_SET_ENCRYPTION         0x000900D7 /* BB add struct */
 #define FSCTL_ENCRYPTION_FSCTL_IO    0x000900DB /* BB add struct */
 #define FSCTL_WRITE_RAW_ENCRYPTED    0x000900DF /* BB add struct */
index 08cdfe5461e3f726650c1216f801d6620694ea5f..622e8824902432e5aae886ce68dca464f504fda3 100644 (file)
@@ -2828,8 +2828,9 @@ static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf)
                 */
                overhead += ngroups * (2 + sbi->s_itb_per_group);
 
-               /* Add the journal blocks as well */
-                overhead += sbi->s_journal->j_maxlen;
+               /* Add the internal journal blocks as well */
+               if (sbi->s_journal && !sbi->journal_bdev)
+                       overhead += sbi->s_journal->j_maxlen;
 
                sbi->s_overhead_last = overhead;
                smp_wmb();
index 5b19760b1de59ddc6340f8845832c031a272a4db..b0c225cdb52cd20ba5927149c338d9749e951f57 100644 (file)
@@ -1825,7 +1825,7 @@ ext4_group_first_block_no(struct super_block *sb, ext4_group_t group_no)
 /*
  * Special error return code only used by dx_probe() and its callers.
  */
-#define ERR_BAD_DX_DIR -75000
+#define ERR_BAD_DX_DIR (-(MAX_ERRNO - 1))
 
 /*
  * Timeout and state flag for lazy initialization inode thread.
@@ -2454,6 +2454,22 @@ static inline void ext4_update_i_disksize(struct inode *inode, loff_t newsize)
        up_write(&EXT4_I(inode)->i_data_sem);
 }
 
+/* Update i_size, i_disksize. Requires i_mutex to avoid races with truncate */
+static inline int ext4_update_inode_size(struct inode *inode, loff_t newsize)
+{
+       int changed = 0;
+
+       if (newsize > inode->i_size) {
+               i_size_write(inode, newsize);
+               changed = 1;
+       }
+       if (newsize > EXT4_I(inode)->i_disksize) {
+               ext4_update_i_disksize(inode, newsize);
+               changed |= 2;
+       }
+       return changed;
+}
+
 struct ext4_group_info {
        unsigned long   bb_state;
        struct rb_root  bb_free_root;
index 76c2df382b7d05619bbe4093d2115ca6dafa617e..74292a71b384e2fd480357a8115c5e4936fa6f20 100644 (file)
@@ -4665,7 +4665,8 @@ retry:
 }
 
 static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset,
-                                 ext4_lblk_t len, int flags, int mode)
+                                 ext4_lblk_t len, loff_t new_size,
+                                 int flags, int mode)
 {
        struct inode *inode = file_inode(file);
        handle_t *handle;
@@ -4674,8 +4675,10 @@ static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset,
        int retries = 0;
        struct ext4_map_blocks map;
        unsigned int credits;
+       loff_t epos;
 
        map.m_lblk = offset;
+       map.m_len = len;
        /*
         * Don't normalize the request if it can fit in one extent so
         * that it doesn't get unnecessarily split into multiple
@@ -4690,9 +4693,7 @@ static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset,
        credits = ext4_chunk_trans_blocks(inode, len);
 
 retry:
-       while (ret >= 0 && ret < len) {
-               map.m_lblk = map.m_lblk + ret;
-               map.m_len = len = len - ret;
+       while (ret >= 0 && len) {
                handle = ext4_journal_start(inode, EXT4_HT_MAP_BLOCKS,
                                            credits);
                if (IS_ERR(handle)) {
@@ -4709,6 +4710,21 @@ retry:
                        ret2 = ext4_journal_stop(handle);
                        break;
                }
+               map.m_lblk += ret;
+               map.m_len = len = len - ret;
+               epos = (loff_t)map.m_lblk << inode->i_blkbits;
+               inode->i_ctime = ext4_current_time(inode);
+               if (new_size) {
+                       if (epos > new_size)
+                               epos = new_size;
+                       if (ext4_update_inode_size(inode, epos) & 0x1)
+                               inode->i_mtime = inode->i_ctime;
+               } else {
+                       if (epos > inode->i_size)
+                               ext4_set_inode_flag(inode,
+                                                   EXT4_INODE_EOFBLOCKS);
+               }
+               ext4_mark_inode_dirty(handle, inode);
                ret2 = ext4_journal_stop(handle);
                if (ret2)
                        break;
@@ -4731,7 +4747,8 @@ static long ext4_zero_range(struct file *file, loff_t offset,
        loff_t new_size = 0;
        int ret = 0;
        int flags;
-       int partial;
+       int credits;
+       int partial_begin, partial_end;
        loff_t start, end;
        ext4_lblk_t lblk;
        struct address_space *mapping = inode->i_mapping;
@@ -4771,7 +4788,8 @@ static long ext4_zero_range(struct file *file, loff_t offset,
 
        if (start < offset || end > offset + len)
                return -EINVAL;
-       partial = (offset + len) & ((1 << blkbits) - 1);
+       partial_begin = offset & ((1 << blkbits) - 1);
+       partial_end = (offset + len) & ((1 << blkbits) - 1);
 
        lblk = start >> blkbits;
        max_blocks = (end >> blkbits);
@@ -4805,7 +4823,7 @@ static long ext4_zero_range(struct file *file, loff_t offset,
                 * If we have a partial block after EOF we have to allocate
                 * the entire block.
                 */
-               if (partial)
+               if (partial_end)
                        max_blocks += 1;
        }
 
@@ -4813,6 +4831,7 @@ static long ext4_zero_range(struct file *file, loff_t offset,
 
                /* Now release the pages and zero block aligned part of pages*/
                truncate_pagecache_range(inode, start, end - 1);
+               inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
 
                /* Wait all existing dio workers, newcomers will block on i_mutex */
                ext4_inode_block_unlocked_dio(inode);
@@ -4825,13 +4844,22 @@ static long ext4_zero_range(struct file *file, loff_t offset,
                if (ret)
                        goto out_dio;
 
-               ret = ext4_alloc_file_blocks(file, lblk, max_blocks, flags,
-                                            mode);
+               ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size,
+                                            flags, mode);
                if (ret)
                        goto out_dio;
        }
+       if (!partial_begin && !partial_end)
+               goto out_dio;
 
-       handle = ext4_journal_start(inode, EXT4_HT_MISC, 4);
+       /*
+        * In worst case we have to writeout two nonadjacent unwritten
+        * blocks and update the inode
+        */
+       credits = (2 * ext4_ext_index_trans_blocks(inode, 2)) + 1;
+       if (ext4_should_journal_data(inode))
+               credits += 2;
+       handle = ext4_journal_start(inode, EXT4_HT_MISC, credits);
        if (IS_ERR(handle)) {
                ret = PTR_ERR(handle);
                ext4_std_error(inode->i_sb, ret);
@@ -4839,12 +4867,8 @@ static long ext4_zero_range(struct file *file, loff_t offset,
        }
 
        inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
-
        if (new_size) {
-               if (new_size > i_size_read(inode))
-                       i_size_write(inode, new_size);
-               if (new_size > EXT4_I(inode)->i_disksize)
-                       ext4_update_i_disksize(inode, new_size);
+               ext4_update_inode_size(inode, new_size);
        } else {
                /*
                * Mark that we allocate beyond EOF so the subsequent truncate
@@ -4853,7 +4877,6 @@ static long ext4_zero_range(struct file *file, loff_t offset,
                if ((offset + len) > i_size_read(inode))
                        ext4_set_inode_flag(inode, EXT4_INODE_EOFBLOCKS);
        }
-
        ext4_mark_inode_dirty(handle, inode);
 
        /* Zero out partial block at the edges of the range */
@@ -4880,13 +4903,11 @@ out_mutex:
 long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
 {
        struct inode *inode = file_inode(file);
-       handle_t *handle;
        loff_t new_size = 0;
        unsigned int max_blocks;
        int ret = 0;
        int flags;
        ext4_lblk_t lblk;
-       struct timespec tv;
        unsigned int blkbits = inode->i_blkbits;
 
        /* Return error if mode is not supported */
@@ -4937,36 +4958,15 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
                        goto out;
        }
 
-       ret = ext4_alloc_file_blocks(file, lblk, max_blocks, flags, mode);
+       ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size,
+                                    flags, mode);
        if (ret)
                goto out;
 
-       handle = ext4_journal_start(inode, EXT4_HT_INODE, 2);
-       if (IS_ERR(handle))
-               goto out;
-
-       tv = inode->i_ctime = ext4_current_time(inode);
-
-       if (new_size) {
-               if (new_size > i_size_read(inode)) {
-                       i_size_write(inode, new_size);
-                       inode->i_mtime = tv;
-               }
-               if (new_size > EXT4_I(inode)->i_disksize)
-                       ext4_update_i_disksize(inode, new_size);
-       } else {
-               /*
-               * Mark that we allocate beyond EOF so the subsequent truncate
-               * can proceed even if the new size is the same as i_size.
-               */
-               if ((offset + len) > i_size_read(inode))
-                       ext4_set_inode_flag(inode, EXT4_INODE_EOFBLOCKS);
+       if (file->f_flags & O_SYNC && EXT4_SB(inode->i_sb)->s_journal) {
+               ret = jbd2_complete_transaction(EXT4_SB(inode->i_sb)->s_journal,
+                                               EXT4_I(inode)->i_sync_tid);
        }
-       ext4_mark_inode_dirty(handle, inode);
-       if (file->f_flags & O_SYNC)
-               ext4_handle_sync(handle);
-
-       ext4_journal_stop(handle);
 out:
        mutex_unlock(&inode->i_mutex);
        trace_ext4_fallocate_exit(inode, offset, max_blocks, ret);
index 367a60c07cf034e6983d8a51cf0eb321394b6209..3aa26e9117c440b7145cd4196433cd1568a9b20b 100644 (file)
@@ -1055,27 +1055,11 @@ static int ext4_write_end(struct file *file,
        } else
                copied = block_write_end(file, mapping, pos,
                                         len, copied, page, fsdata);
-
        /*
-        * No need to use i_size_read() here, the i_size
-        * cannot change under us because we hole i_mutex.
-        *
-        * But it's important to update i_size while still holding page lock:
+        * it's important to update i_size while still holding page lock:
         * page writeout could otherwise come in and zero beyond i_size.
         */
-       if (pos + copied > inode->i_size) {
-               i_size_write(inode, pos + copied);
-               i_size_changed = 1;
-       }
-
-       if (pos + copied > EXT4_I(inode)->i_disksize) {
-               /* We need to mark inode dirty even if
-                * new_i_size is less that inode->i_size
-                * but greater than i_disksize. (hint delalloc)
-                */
-               ext4_update_i_disksize(inode, (pos + copied));
-               i_size_changed = 1;
-       }
+       i_size_changed = ext4_update_inode_size(inode, pos + copied);
        unlock_page(page);
        page_cache_release(page);
 
@@ -1123,7 +1107,7 @@ static int ext4_journalled_write_end(struct file *file,
        int ret = 0, ret2;
        int partial = 0;
        unsigned from, to;
-       loff_t new_i_size;
+       int size_changed = 0;
 
        trace_ext4_journalled_write_end(inode, pos, len, copied);
        from = pos & (PAGE_CACHE_SIZE - 1);
@@ -1146,20 +1130,18 @@ static int ext4_journalled_write_end(struct file *file,
                if (!partial)
                        SetPageUptodate(page);
        }
-       new_i_size = pos + copied;
-       if (new_i_size > inode->i_size)
-               i_size_write(inode, pos+copied);
+       size_changed = ext4_update_inode_size(inode, pos + copied);
        ext4_set_inode_state(inode, EXT4_STATE_JDATA);
        EXT4_I(inode)->i_datasync_tid = handle->h_transaction->t_tid;
-       if (new_i_size > EXT4_I(inode)->i_disksize) {
-               ext4_update_i_disksize(inode, new_i_size);
+       unlock_page(page);
+       page_cache_release(page);
+
+       if (size_changed) {
                ret2 = ext4_mark_inode_dirty(handle, inode);
                if (!ret)
                        ret = ret2;
        }
 
-       unlock_page(page);
-       page_cache_release(page);
        if (pos + len > inode->i_size && ext4_can_truncate(inode))
                /* if we have allocated more blocks and copied
                 * less. We will have blocks allocated outside
@@ -2095,6 +2077,7 @@ static int mpage_map_and_submit_extent(handle_t *handle,
        struct ext4_map_blocks *map = &mpd->map;
        int err;
        loff_t disksize;
+       int progress = 0;
 
        mpd->io_submit.io_end->offset =
                                ((loff_t)map->m_lblk) << inode->i_blkbits;
@@ -2111,8 +2094,11 @@ static int mpage_map_and_submit_extent(handle_t *handle,
                         * is non-zero, a commit should free up blocks.
                         */
                        if ((err == -ENOMEM) ||
-                           (err == -ENOSPC && ext4_count_free_clusters(sb)))
+                           (err == -ENOSPC && ext4_count_free_clusters(sb))) {
+                               if (progress)
+                                       goto update_disksize;
                                return err;
+                       }
                        ext4_msg(sb, KERN_CRIT,
                                 "Delayed block allocation failed for "
                                 "inode %lu at logical offset %llu with"
@@ -2129,15 +2115,17 @@ static int mpage_map_and_submit_extent(handle_t *handle,
                        *give_up_on_write = true;
                        return err;
                }
+               progress = 1;
                /*
                 * Update buffer state, submit mapped pages, and get us new
                 * extent to map
                 */
                err = mpage_map_and_submit_buffers(mpd);
                if (err < 0)
-                       return err;
+                       goto update_disksize;
        } while (map->m_len);
 
+update_disksize:
        /*
         * Update on-disk size after IO is submitted.  Races with
         * truncate are avoided by checking i_size under i_data_sem.
index 956027711faf29aa52669d27061794840e332e08..8b0f9ef517d690ea0ede0958c8aa726aebb86b35 100644 (file)
@@ -1412,6 +1412,8 @@ static void mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b,
        int last = first + count - 1;
        struct super_block *sb = e4b->bd_sb;
 
+       if (WARN_ON(count == 0))
+               return;
        BUG_ON(last >= (sb->s_blocksize << 3));
        assert_spin_locked(ext4_group_lock_ptr(sb, e4b->bd_group));
        /* Don't bother if the block group is corrupt. */
@@ -3221,6 +3223,8 @@ static void ext4_discard_allocated_blocks(struct ext4_allocation_context *ac)
        int err;
 
        if (pa == NULL) {
+               if (ac->ac_f_ex.fe_len == 0)
+                       return;
                err = ext4_mb_load_buddy(ac->ac_sb, ac->ac_f_ex.fe_group, &e4b);
                if (err) {
                        /*
@@ -3235,6 +3239,7 @@ static void ext4_discard_allocated_blocks(struct ext4_allocation_context *ac)
                mb_free_blocks(ac->ac_inode, &e4b, ac->ac_f_ex.fe_start,
                               ac->ac_f_ex.fe_len);
                ext4_unlock_group(ac->ac_sb, ac->ac_f_ex.fe_group);
+               ext4_mb_unload_buddy(&e4b);
                return;
        }
        if (pa->pa_type == MB_INODE_PA)
index b147a67baa0d976d026857308350d85b8de72e01..90a3cdca3f88b8d30adffe6b6dba52d613b1c9c2 100644 (file)
@@ -1227,7 +1227,7 @@ static struct buffer_head * ext4_find_entry (struct inode *dir,
                                   buffer */
        int num = 0;
        ext4_lblk_t  nblocks;
-       int i, err;
+       int i, err = 0;
        int namelen;
 
        *res_dir = NULL;
@@ -1264,7 +1264,11 @@ static struct buffer_head * ext4_find_entry (struct inode *dir,
                 * return.  Otherwise, fall back to doing a search the
                 * old fashioned way.
                 */
-               if (bh || (err != ERR_BAD_DX_DIR))
+               if (err == -ENOENT)
+                       return NULL;
+               if (err && err != ERR_BAD_DX_DIR)
+                       return ERR_PTR(err);
+               if (bh)
                        return bh;
                dxtrace(printk(KERN_DEBUG "ext4_find_entry: dx failed, "
                               "falling back\n"));
@@ -1295,6 +1299,11 @@ restart:
                                }
                                num++;
                                bh = ext4_getblk(NULL, dir, b++, 0, &err);
+                               if (unlikely(err)) {
+                                       if (ra_max == 0)
+                                               return ERR_PTR(err);
+                                       break;
+                               }
                                bh_use[ra_max] = bh;
                                if (bh)
                                        ll_rw_block(READ | REQ_META | REQ_PRIO,
@@ -1417,6 +1426,8 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi
                return ERR_PTR(-ENAMETOOLONG);
 
        bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL);
+       if (IS_ERR(bh))
+               return (struct dentry *) bh;
        inode = NULL;
        if (bh) {
                __u32 ino = le32_to_cpu(de->inode);
@@ -1450,6 +1461,8 @@ struct dentry *ext4_get_parent(struct dentry *child)
        struct buffer_head *bh;
 
        bh = ext4_find_entry(child->d_inode, &dotdot, &de, NULL);
+       if (IS_ERR(bh))
+               return (struct dentry *) bh;
        if (!bh)
                return ERR_PTR(-ENOENT);
        ino = le32_to_cpu(de->inode);
@@ -2727,6 +2740,8 @@ static int ext4_rmdir(struct inode *dir, struct dentry *dentry)
 
        retval = -ENOENT;
        bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL);
+       if (IS_ERR(bh))
+               return PTR_ERR(bh);
        if (!bh)
                goto end_rmdir;
 
@@ -2794,6 +2809,8 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry)
 
        retval = -ENOENT;
        bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL);
+       if (IS_ERR(bh))
+               return PTR_ERR(bh);
        if (!bh)
                goto end_unlink;
 
@@ -3121,6 +3138,8 @@ static int ext4_find_delete_entry(handle_t *handle, struct inode *dir,
        struct ext4_dir_entry_2 *de;
 
        bh = ext4_find_entry(dir, d_name, &de, NULL);
+       if (IS_ERR(bh))
+               return PTR_ERR(bh);
        if (bh) {
                retval = ext4_delete_entry(handle, dir, de, bh);
                brelse(bh);
@@ -3128,7 +3147,8 @@ static int ext4_find_delete_entry(handle_t *handle, struct inode *dir,
        return retval;
 }
 
-static void ext4_rename_delete(handle_t *handle, struct ext4_renament *ent)
+static void ext4_rename_delete(handle_t *handle, struct ext4_renament *ent,
+                              int force_reread)
 {
        int retval;
        /*
@@ -3140,7 +3160,8 @@ static void ext4_rename_delete(handle_t *handle, struct ext4_renament *ent)
        if (le32_to_cpu(ent->de->inode) != ent->inode->i_ino ||
            ent->de->name_len != ent->dentry->d_name.len ||
            strncmp(ent->de->name, ent->dentry->d_name.name,
-                   ent->de->name_len)) {
+                   ent->de->name_len) ||
+           force_reread) {
                retval = ext4_find_delete_entry(handle, ent->dir,
                                                &ent->dentry->d_name);
        } else {
@@ -3191,6 +3212,7 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
                .dentry = new_dentry,
                .inode = new_dentry->d_inode,
        };
+       int force_reread;
        int retval;
 
        dquot_initialize(old.dir);
@@ -3202,6 +3224,8 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
                dquot_initialize(new.inode);
 
        old.bh = ext4_find_entry(old.dir, &old.dentry->d_name, &old.de, NULL);
+       if (IS_ERR(old.bh))
+               return PTR_ERR(old.bh);
        /*
         *  Check for inode number is _not_ due to possible IO errors.
         *  We might rmdir the source, keep it as pwd of some process
@@ -3214,6 +3238,10 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
 
        new.bh = ext4_find_entry(new.dir, &new.dentry->d_name,
                                 &new.de, &new.inlined);
+       if (IS_ERR(new.bh)) {
+               retval = PTR_ERR(new.bh);
+               goto end_rename;
+       }
        if (new.bh) {
                if (!new.inode) {
                        brelse(new.bh);
@@ -3246,6 +3274,15 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
                if (retval)
                        goto end_rename;
        }
+       /*
+        * If we're renaming a file within an inline_data dir and adding or
+        * setting the new dirent causes a conversion from inline_data to
+        * extents/blockmap, we need to force the dirent delete code to
+        * re-read the directory, or else we end up trying to delete a dirent
+        * from what is now the extent tree root (or a block map).
+        */
+       force_reread = (new.dir->i_ino == old.dir->i_ino &&
+                       ext4_test_inode_flag(new.dir, EXT4_INODE_INLINE_DATA));
        if (!new.bh) {
                retval = ext4_add_entry(handle, new.dentry, old.inode);
                if (retval)
@@ -3256,6 +3293,9 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
                if (retval)
                        goto end_rename;
        }
+       if (force_reread)
+               force_reread = !ext4_test_inode_flag(new.dir,
+                                                    EXT4_INODE_INLINE_DATA);
 
        /*
         * Like most other Unix systems, set the ctime for inodes on a
@@ -3267,7 +3307,7 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
        /*
         * ok, that's it
         */
-       ext4_rename_delete(handle, &old);
+       ext4_rename_delete(handle, &old, force_reread);
 
        if (new.inode) {
                ext4_dec_count(handle, new.inode);
@@ -3330,6 +3370,8 @@ static int ext4_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
 
        old.bh = ext4_find_entry(old.dir, &old.dentry->d_name,
                                 &old.de, &old.inlined);
+       if (IS_ERR(old.bh))
+               return PTR_ERR(old.bh);
        /*
         *  Check for inode number is _not_ due to possible IO errors.
         *  We might rmdir the source, keep it as pwd of some process
@@ -3342,6 +3384,10 @@ static int ext4_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
 
        new.bh = ext4_find_entry(new.dir, &new.dentry->d_name,
                                 &new.de, &new.inlined);
+       if (IS_ERR(new.bh)) {
+               retval = PTR_ERR(new.bh);
+               goto end_rename;
+       }
 
        /* RENAME_EXCHANGE case: old *and* new must both exist */
        if (!new.bh || le32_to_cpu(new.de->inode) != new.inode->i_ino)
index 32b43ad154b99742a6476b218a62fd568466381c..0b28b36e7915ccf2e440c8782c618473f31d9576 100644 (file)
@@ -3181,9 +3181,9 @@ static int set_journal_csum_feature_set(struct super_block *sb)
 
        if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
                                       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
-               /* journal checksum v2 */
+               /* journal checksum v3 */
                compat = 0;
-               incompat = JBD2_FEATURE_INCOMPAT_CSUM_V2;
+               incompat = JBD2_FEATURE_INCOMPAT_CSUM_V3;
        } else {
                /* journal checksum v1 */
                compat = JBD2_FEATURE_COMPAT_CHECKSUM;
@@ -3205,6 +3205,7 @@ static int set_journal_csum_feature_set(struct super_block *sb)
                jbd2_journal_clear_features(sbi->s_journal,
                                JBD2_FEATURE_COMPAT_CHECKSUM, 0,
                                JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT |
+                               JBD2_FEATURE_INCOMPAT_CSUM_V3 |
                                JBD2_FEATURE_INCOMPAT_CSUM_V2);
        }
 
index 214fe1054fceef32e74589e06a8d89203d9cc601..736a348509f7d6cfc6041d4e7f8838972c3413e3 100644 (file)
@@ -23,7 +23,7 @@ config F2FS_STAT_FS
          mounted as f2fs. Each file shows the whole f2fs information.
 
          /sys/kernel/debug/f2fs/status includes:
-           - major file system information managed by f2fs currently
+           - major filesystem information managed by f2fs currently
            - average SIT information about whole segments
            - current memory footprint consumed by f2fs.
 
@@ -68,6 +68,6 @@ config F2FS_CHECK_FS
        bool "F2FS consistency checking feature"
        depends on F2FS_FS
        help
-         Enables BUG_ONs which check the file system consistency in runtime.
+         Enables BUG_ONs which check the filesystem consistency in runtime.
 
          If you want to improve the performance, say N.
index 6aeed5bada52b1e6bdf9d1bc8228c9e69fb35b13..ec3b7a5381fa3fca2165aa9bcdb7402c0eace5bc 100644 (file)
@@ -160,14 +160,11 @@ static int f2fs_write_meta_page(struct page *page,
                goto redirty_out;
        if (wbc->for_reclaim)
                goto redirty_out;
-
-       /* Should not write any meta pages, if any IO error was occurred */
-       if (unlikely(is_set_ckpt_flags(F2FS_CKPT(sbi), CP_ERROR_FLAG)))
-               goto no_write;
+       if (unlikely(f2fs_cp_error(sbi)))
+               goto redirty_out;
 
        f2fs_wait_on_page_writeback(page, META);
        write_meta_page(sbi, page);
-no_write:
        dec_page_count(sbi, F2FS_DIRTY_META);
        unlock_page(page);
        return 0;
@@ -348,7 +345,7 @@ bool exist_written_data(struct f2fs_sb_info *sbi, nid_t ino, int mode)
        return e ? true : false;
 }
 
-static void release_dirty_inode(struct f2fs_sb_info *sbi)
+void release_dirty_inode(struct f2fs_sb_info *sbi)
 {
        struct ino_entry *e, *tmp;
        int i;
@@ -446,8 +443,8 @@ static void write_orphan_inodes(struct f2fs_sb_info *sbi, block_t start_blk)
        struct f2fs_orphan_block *orphan_blk = NULL;
        unsigned int nentries = 0;
        unsigned short index;
-       unsigned short orphan_blocks = (unsigned short)((sbi->n_orphans +
-               (F2FS_ORPHANS_PER_BLOCK - 1)) / F2FS_ORPHANS_PER_BLOCK);
+       unsigned short orphan_blocks =
+                       (unsigned short)GET_ORPHAN_BLOCKS(sbi->n_orphans);
        struct page *page = NULL;
        struct ino_entry *orphan = NULL;
 
@@ -737,7 +734,7 @@ retry:
 /*
  * Freeze all the FS-operations for checkpoint.
  */
-static void block_operations(struct f2fs_sb_info *sbi)
+static int block_operations(struct f2fs_sb_info *sbi)
 {
        struct writeback_control wbc = {
                .sync_mode = WB_SYNC_ALL,
@@ -745,6 +742,7 @@ static void block_operations(struct f2fs_sb_info *sbi)
                .for_reclaim = 0,
        };
        struct blk_plug plug;
+       int err = 0;
 
        blk_start_plug(&plug);
 
@@ -754,11 +752,15 @@ retry_flush_dents:
        if (get_pages(sbi, F2FS_DIRTY_DENTS)) {
                f2fs_unlock_all(sbi);
                sync_dirty_dir_inodes(sbi);
+               if (unlikely(f2fs_cp_error(sbi))) {
+                       err = -EIO;
+                       goto out;
+               }
                goto retry_flush_dents;
        }
 
        /*
-        * POR: we should ensure that there is no dirty node pages
+        * POR: we should ensure that there are no dirty node pages
         * until finishing nat/sit flush.
         */
 retry_flush_nodes:
@@ -767,9 +769,16 @@ retry_flush_nodes:
        if (get_pages(sbi, F2FS_DIRTY_NODES)) {
                up_write(&sbi->node_write);
                sync_node_pages(sbi, 0, &wbc);
+               if (unlikely(f2fs_cp_error(sbi))) {
+                       f2fs_unlock_all(sbi);
+                       err = -EIO;
+                       goto out;
+               }
                goto retry_flush_nodes;
        }
+out:
        blk_finish_plug(&plug);
+       return err;
 }
 
 static void unblock_operations(struct f2fs_sb_info *sbi)
@@ -813,8 +822,11 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
        discard_next_dnode(sbi, NEXT_FREE_BLKADDR(sbi, curseg));
 
        /* Flush all the NAT/SIT pages */
-       while (get_pages(sbi, F2FS_DIRTY_META))
+       while (get_pages(sbi, F2FS_DIRTY_META)) {
                sync_meta_pages(sbi, META, LONG_MAX);
+               if (unlikely(f2fs_cp_error(sbi)))
+                       return;
+       }
 
        next_free_nid(sbi, &last_nid);
 
@@ -825,7 +837,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
        ckpt->elapsed_time = cpu_to_le64(get_mtime(sbi));
        ckpt->valid_block_count = cpu_to_le64(valid_user_blocks(sbi));
        ckpt->free_segment_count = cpu_to_le32(free_segments(sbi));
-       for (i = 0; i < 3; i++) {
+       for (i = 0; i < NR_CURSEG_NODE_TYPE; i++) {
                ckpt->cur_node_segno[i] =
                        cpu_to_le32(curseg_segno(sbi, i + CURSEG_HOT_NODE));
                ckpt->cur_node_blkoff[i] =
@@ -833,7 +845,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
                ckpt->alloc_type[i + CURSEG_HOT_NODE] =
                                curseg_alloc_type(sbi, i + CURSEG_HOT_NODE);
        }
-       for (i = 0; i < 3; i++) {
+       for (i = 0; i < NR_CURSEG_DATA_TYPE; i++) {
                ckpt->cur_data_segno[i] =
                        cpu_to_le32(curseg_segno(sbi, i + CURSEG_HOT_DATA));
                ckpt->cur_data_blkoff[i] =
@@ -848,24 +860,23 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
 
        /* 2 cp  + n data seg summary + orphan inode blocks */
        data_sum_blocks = npages_for_summary_flush(sbi);
-       if (data_sum_blocks < 3)
+       if (data_sum_blocks < NR_CURSEG_DATA_TYPE)
                set_ckpt_flags(ckpt, CP_COMPACT_SUM_FLAG);
        else
                clear_ckpt_flags(ckpt, CP_COMPACT_SUM_FLAG);
 
-       orphan_blocks = (sbi->n_orphans + F2FS_ORPHANS_PER_BLOCK - 1)
-                                       / F2FS_ORPHANS_PER_BLOCK;
+       orphan_blocks = GET_ORPHAN_BLOCKS(sbi->n_orphans);
        ckpt->cp_pack_start_sum = cpu_to_le32(1 + cp_payload_blks +
                        orphan_blocks);
 
        if (is_umount) {
                set_ckpt_flags(ckpt, CP_UMOUNT_FLAG);
-               ckpt->cp_pack_total_block_count = cpu_to_le32(+
+               ckpt->cp_pack_total_block_count = cpu_to_le32(F2FS_CP_PACKS+
                                cp_payload_blks + data_sum_blocks +
                                orphan_blocks + NR_CURSEG_NODE_TYPE);
        } else {
                clear_ckpt_flags(ckpt, CP_UMOUNT_FLAG);
-               ckpt->cp_pack_total_block_count = cpu_to_le32(2 +
+               ckpt->cp_pack_total_block_count = cpu_to_le32(F2FS_CP_PACKS +
                                cp_payload_blks + data_sum_blocks +
                                orphan_blocks);
        }
@@ -924,6 +935,9 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
        /* wait for previous submitted node/meta pages writeback */
        wait_on_all_pages_writeback(sbi);
 
+       if (unlikely(f2fs_cp_error(sbi)))
+               return;
+
        filemap_fdatawait_range(NODE_MAPPING(sbi), 0, LONG_MAX);
        filemap_fdatawait_range(META_MAPPING(sbi), 0, LONG_MAX);
 
@@ -934,15 +948,17 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
        /* Here, we only have one bio having CP pack */
        sync_meta_pages(sbi, META_FLUSH, LONG_MAX);
 
-       if (!is_set_ckpt_flags(ckpt, CP_ERROR_FLAG)) {
-               clear_prefree_segments(sbi);
-               release_dirty_inode(sbi);
-               F2FS_RESET_SB_DIRT(sbi);
-       }
+       release_dirty_inode(sbi);
+
+       if (unlikely(f2fs_cp_error(sbi)))
+               return;
+
+       clear_prefree_segments(sbi);
+       F2FS_RESET_SB_DIRT(sbi);
 }
 
 /*
- * We guarantee that this checkpoint procedure should not fail.
+ * We guarantee that this checkpoint procedure will not fail.
  */
 void write_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
 {
@@ -952,7 +968,13 @@ void write_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
        trace_f2fs_write_checkpoint(sbi->sb, is_umount, "start block_ops");
 
        mutex_lock(&sbi->cp_mutex);
-       block_operations(sbi);
+
+       if (!sbi->s_dirty)
+               goto out;
+       if (unlikely(f2fs_cp_error(sbi)))
+               goto out;
+       if (block_operations(sbi))
+               goto out;
 
        trace_f2fs_write_checkpoint(sbi->sb, is_umount, "finish block_ops");
 
@@ -976,9 +998,9 @@ void write_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
        do_checkpoint(sbi, is_umount);
 
        unblock_operations(sbi);
-       mutex_unlock(&sbi->cp_mutex);
-
        stat_inc_cp_count(sbi->stat_info);
+out:
+       mutex_unlock(&sbi->cp_mutex);
        trace_f2fs_write_checkpoint(sbi->sb, is_umount, "finish checkpoint");
 }
 
@@ -999,8 +1021,8 @@ void init_ino_entry_info(struct f2fs_sb_info *sbi)
         * for cp pack we can have max 1020*504 orphan entries
         */
        sbi->n_orphans = 0;
-       sbi->max_orphans = (sbi->blocks_per_seg - 2 - NR_CURSEG_TYPE)
-                               * F2FS_ORPHANS_PER_BLOCK;
+       sbi->max_orphans = (sbi->blocks_per_seg - F2FS_CP_PACKS -
+                       NR_CURSEG_TYPE) * F2FS_ORPHANS_PER_BLOCK;
 }
 
 int __init create_checkpoint_caches(void)
index 03313099c51c44b957f84fb6ec4a6ab698eee970..76de83e25a891d8cf85c4b84d2641dbf414a77e6 100644 (file)
@@ -53,7 +53,7 @@ static void f2fs_write_end_io(struct bio *bio, int err)
                struct page *page = bvec->bv_page;
 
                if (unlikely(err)) {
-                       SetPageError(page);
+                       set_page_dirty(page);
                        set_bit(AS_EIO, &page->mapping->flags);
                        f2fs_stop_checkpoint(sbi);
                }
@@ -691,7 +691,7 @@ get_next:
                        allocated = true;
                        blkaddr = dn.data_blkaddr;
                }
-               /* Give more consecutive addresses for the read ahead */
+               /* Give more consecutive addresses for the readahead */
                if (blkaddr == (bh_result->b_blocknr + ofs)) {
                        ofs++;
                        dn.ofs_in_node++;
@@ -739,7 +739,7 @@ static int f2fs_read_data_page(struct file *file, struct page *page)
 
        trace_f2fs_readpage(page, DATA);
 
-       /* If the file has inline data, try to read it directlly */
+       /* If the file has inline data, try to read it directly */
        if (f2fs_has_inline_data(inode))
                ret = f2fs_read_inline_data(inode, page);
        else
@@ -836,10 +836,19 @@ write:
 
        /* Dentry blocks are controlled by checkpoint */
        if (S_ISDIR(inode->i_mode)) {
+               if (unlikely(f2fs_cp_error(sbi)))
+                       goto redirty_out;
                err = do_write_data_page(page, &fio);
                goto done;
        }
 
+       /* we should bypass data pages to proceed the kworkder jobs */
+       if (unlikely(f2fs_cp_error(sbi))) {
+               SetPageError(page);
+               unlock_page(page);
+               return 0;
+       }
+
        if (!wbc->for_reclaim)
                need_balance_fs = true;
        else if (has_not_enough_free_secs(sbi, 0))
@@ -927,7 +936,7 @@ static void f2fs_write_failed(struct address_space *mapping, loff_t to)
 
        if (to > inode->i_size) {
                truncate_pagecache(inode, inode->i_size);
-               truncate_blocks(inode, inode->i_size);
+               truncate_blocks(inode, inode->i_size, true);
        }
 }
 
@@ -946,7 +955,7 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
 
        f2fs_balance_fs(sbi);
 repeat:
-       err = f2fs_convert_inline_data(inode, pos + len);
+       err = f2fs_convert_inline_data(inode, pos + len, NULL);
        if (err)
                goto fail;
 
index a441ba33be11bd2f12b1a948cad200ad22be33d6..fecebdbfd7810fbccf61c984c9e029c345b7fdef 100644 (file)
@@ -32,7 +32,7 @@ static void update_general_status(struct f2fs_sb_info *sbi)
        struct f2fs_stat_info *si = F2FS_STAT(sbi);
        int i;
 
-       /* valid check of the segment numbers */
+       /* validation check of the segment numbers */
        si->hit_ext = sbi->read_hit_ext;
        si->total_ext = sbi->total_hit_ext;
        si->ndirty_node = get_pages(sbi, F2FS_DIRTY_NODES);
@@ -152,7 +152,7 @@ static void update_mem_info(struct f2fs_sb_info *sbi)
        si->base_mem += NR_DIRTY_TYPE * f2fs_bitmap_size(TOTAL_SEGS(sbi));
        si->base_mem += f2fs_bitmap_size(TOTAL_SECS(sbi));
 
-       /* buld nm */
+       /* build nm */
        si->base_mem += sizeof(struct f2fs_nm_info);
        si->base_mem += __bitmap_size(sbi, NAT_BITMAP);
 
index bcf893c3d9036d0eb743ff8c34bae2eda23e9582..155fb056b7f1ab0424beb480b328bd12d0c18aff 100644 (file)
@@ -124,7 +124,7 @@ static struct f2fs_dir_entry *find_in_block(struct page *dentry_page,
 
                /*
                 * For the most part, it should be a bug when name_len is zero.
-                * We stop here for figuring out where the bugs are occurred.
+                * We stop here for figuring out where the bugs has occurred.
                 */
                f2fs_bug_on(!de->name_len);
 
@@ -391,7 +391,7 @@ put_error:
 error:
        /* once the failed inode becomes a bad inode, i_mode is S_IFREG */
        truncate_inode_pages(&inode->i_data, 0);
-       truncate_blocks(inode, 0);
+       truncate_blocks(inode, 0, false);
        remove_dirty_dir_inode(inode);
        remove_inode_page(inode);
        return ERR_PTR(err);
@@ -563,7 +563,7 @@ fail:
 }
 
 /*
- * It only removes the dentry from the dentry page,corresponding name
+ * It only removes the dentry from the dentry page, corresponding name
  * entry in name page does not need to be touched during deletion.
  */
 void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
index 4dab5338a97af496ad6f5ee5867a6e6457a03ec5..e921242186f6a1e8af2a128460db45b064027b67 100644 (file)
@@ -24,7 +24,7 @@
 #define f2fs_bug_on(condition) BUG_ON(condition)
 #define f2fs_down_write(x, y)  down_write_nest_lock(x, y)
 #else
-#define f2fs_bug_on(condition)
+#define f2fs_bug_on(condition) WARN_ON(condition)
 #define f2fs_down_write(x, y)  down_write(x)
 #endif
 
@@ -395,7 +395,7 @@ enum count_type {
 };
 
 /*
- * The below are the page types of bios used in submti_bio().
+ * The below are the page types of bios used in submit_bio().
  * The available types are:
  * DATA                        User data pages. It operates as async mode.
  * NODE                        Node pages. It operates as async mode.
@@ -470,7 +470,7 @@ struct f2fs_sb_info {
        struct list_head dir_inode_list;        /* dir inode list */
        spinlock_t dir_inode_lock;              /* for dir inode list lock */
 
-       /* basic file system units */
+       /* basic filesystem units */
        unsigned int log_sectors_per_block;     /* log2 sectors per block */
        unsigned int log_blocksize;             /* log2 block size */
        unsigned int blocksize;                 /* block size */
@@ -799,7 +799,7 @@ static inline block_t __start_cp_addr(struct f2fs_sb_info *sbi)
 
        /*
         * odd numbered checkpoint should at cp segment 0
-        * and even segent must be at cp segment 1
+        * and even segment must be at cp segment 1
         */
        if (!(ckpt_version & 1))
                start_addr += sbi->blocks_per_seg;
@@ -1096,6 +1096,11 @@ static inline int f2fs_readonly(struct super_block *sb)
        return sb->s_flags & MS_RDONLY;
 }
 
+static inline bool f2fs_cp_error(struct f2fs_sb_info *sbi)
+{
+       return is_set_ckpt_flags(sbi->ckpt, CP_ERROR_FLAG);
+}
+
 static inline void f2fs_stop_checkpoint(struct f2fs_sb_info *sbi)
 {
        set_ckpt_flags(sbi->ckpt, CP_ERROR_FLAG);
@@ -1117,7 +1122,7 @@ static inline void f2fs_stop_checkpoint(struct f2fs_sb_info *sbi)
  */
 int f2fs_sync_file(struct file *, loff_t, loff_t, int);
 void truncate_data_blocks(struct dnode_of_data *);
-int truncate_blocks(struct inode *, u64);
+int truncate_blocks(struct inode *, u64, bool);
 void f2fs_truncate(struct inode *);
 int f2fs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
 int f2fs_setattr(struct dentry *, struct iattr *);
@@ -1202,10 +1207,8 @@ int sync_node_pages(struct f2fs_sb_info *, nid_t, struct writeback_control *);
 bool alloc_nid(struct f2fs_sb_info *, nid_t *);
 void alloc_nid_done(struct f2fs_sb_info *, nid_t);
 void alloc_nid_failed(struct f2fs_sb_info *, nid_t);
-void recover_node_page(struct f2fs_sb_info *, struct page *,
-               struct f2fs_summary *, struct node_info *, block_t);
 void recover_inline_xattr(struct inode *, struct page *);
-bool recover_xattr_data(struct inode *, struct page *, block_t);
+void recover_xattr_data(struct inode *, struct page *, block_t);
 int recover_inode_page(struct f2fs_sb_info *, struct page *);
 int restore_node_summary(struct f2fs_sb_info *, unsigned int,
                                struct f2fs_summary_block *);
@@ -1238,8 +1241,6 @@ void write_data_page(struct page *, struct dnode_of_data *, block_t *,
 void rewrite_data_page(struct page *, block_t, struct f2fs_io_info *);
 void recover_data_page(struct f2fs_sb_info *, struct page *,
                                struct f2fs_summary *, block_t, block_t);
-void rewrite_node_page(struct f2fs_sb_info *, struct page *,
-                               struct f2fs_summary *, block_t, block_t);
 void allocate_data_block(struct f2fs_sb_info *, struct page *,
                block_t, block_t *, struct f2fs_summary *, int);
 void f2fs_wait_on_page_writeback(struct page *, enum page_type);
@@ -1262,6 +1263,7 @@ int ra_meta_pages(struct f2fs_sb_info *, int, int, int);
 long sync_meta_pages(struct f2fs_sb_info *, enum page_type, long);
 void add_dirty_inode(struct f2fs_sb_info *, nid_t, int type);
 void remove_dirty_inode(struct f2fs_sb_info *, nid_t, int type);
+void release_dirty_inode(struct f2fs_sb_info *);
 bool exist_written_data(struct f2fs_sb_info *, nid_t, int);
 int acquire_orphan_inode(struct f2fs_sb_info *);
 void release_orphan_inode(struct f2fs_sb_info *);
@@ -1439,8 +1441,8 @@ extern const struct inode_operations f2fs_special_inode_operations;
  */
 bool f2fs_may_inline(struct inode *);
 int f2fs_read_inline_data(struct inode *, struct page *);
-int f2fs_convert_inline_data(struct inode *, pgoff_t);
+int f2fs_convert_inline_data(struct inode *, pgoff_t, struct page *);
 int f2fs_write_inline_data(struct inode *, struct page *, unsigned int);
 void truncate_inline_data(struct inode *, u64);
-int recover_inline_data(struct inode *, struct page *);
+bool recover_inline_data(struct inode *, struct page *);
 #endif
index 208f1a9bd569b6d2c7afafa20c5a5dff9f9b39d1..060aee65aee801d61f7ab5f6b2666a60c0c3363a 100644 (file)
@@ -41,6 +41,11 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma,
 
        sb_start_pagefault(inode->i_sb);
 
+       /* force to convert with normal data indices */
+       err = f2fs_convert_inline_data(inode, MAX_INLINE_DATA + 1, page);
+       if (err)
+               goto out;
+
        /* block allocation */
        f2fs_lock_op(sbi);
        set_new_dnode(&dn, inode, NULL, NULL, 0);
@@ -110,6 +115,25 @@ static int get_parent_ino(struct inode *inode, nid_t *pino)
        return 1;
 }
 
+static inline bool need_do_checkpoint(struct inode *inode)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       bool need_cp = false;
+
+       if (!S_ISREG(inode->i_mode) || inode->i_nlink != 1)
+               need_cp = true;
+       else if (file_wrong_pino(inode))
+               need_cp = true;
+       else if (!space_for_roll_forward(sbi))
+               need_cp = true;
+       else if (!is_checkpointed_node(sbi, F2FS_I(inode)->i_pino))
+               need_cp = true;
+       else if (F2FS_I(inode)->xattr_ver == cur_cp_version(F2FS_CKPT(sbi)))
+               need_cp = true;
+
+       return need_cp;
+}
+
 int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
 {
        struct inode *inode = file->f_mapping->host;
@@ -154,23 +178,12 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
        /* guarantee free sections for fsync */
        f2fs_balance_fs(sbi);
 
-       down_read(&fi->i_sem);
-
        /*
         * Both of fdatasync() and fsync() are able to be recovered from
         * sudden-power-off.
         */
-       if (!S_ISREG(inode->i_mode) || inode->i_nlink != 1)
-               need_cp = true;
-       else if (file_wrong_pino(inode))
-               need_cp = true;
-       else if (!space_for_roll_forward(sbi))
-               need_cp = true;
-       else if (!is_checkpointed_node(sbi, F2FS_I(inode)->i_pino))
-               need_cp = true;
-       else if (F2FS_I(inode)->xattr_ver == cur_cp_version(F2FS_CKPT(sbi)))
-               need_cp = true;
-
+       down_read(&fi->i_sem);
+       need_cp = need_do_checkpoint(inode);
        up_read(&fi->i_sem);
 
        if (need_cp) {
@@ -288,7 +301,7 @@ static loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence)
                if (err && err != -ENOENT) {
                        goto fail;
                } else if (err == -ENOENT) {
-                       /* direct node is not exist */
+                       /* direct node does not exists */
                        if (whence == SEEK_DATA) {
                                pgofs = PGOFS_OF_NEXT_DNODE(pgofs,
                                                        F2FS_I(inode));
@@ -417,7 +430,7 @@ out:
        f2fs_put_page(page, 1);
 }
 
-int truncate_blocks(struct inode *inode, u64 from)
+int truncate_blocks(struct inode *inode, u64 from, bool lock)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
        unsigned int blocksize = inode->i_sb->s_blocksize;
@@ -433,14 +446,16 @@ int truncate_blocks(struct inode *inode, u64 from)
        free_from = (pgoff_t)
                        ((from + blocksize - 1) >> (sbi->log_blocksize));
 
-       f2fs_lock_op(sbi);
+       if (lock)
+               f2fs_lock_op(sbi);
 
        set_new_dnode(&dn, inode, NULL, NULL, 0);
        err = get_dnode_of_data(&dn, free_from, LOOKUP_NODE);
        if (err) {
                if (err == -ENOENT)
                        goto free_next;
-               f2fs_unlock_op(sbi);
+               if (lock)
+                       f2fs_unlock_op(sbi);
                trace_f2fs_truncate_blocks_exit(inode, err);
                return err;
        }
@@ -458,7 +473,8 @@ int truncate_blocks(struct inode *inode, u64 from)
        f2fs_put_dnode(&dn);
 free_next:
        err = truncate_inode_blocks(inode, free_from);
-       f2fs_unlock_op(sbi);
+       if (lock)
+               f2fs_unlock_op(sbi);
 done:
        /* lastly zero out the first data page */
        truncate_partial_data_page(inode, from);
@@ -475,7 +491,7 @@ void f2fs_truncate(struct inode *inode)
 
        trace_f2fs_truncate(inode);
 
-       if (!truncate_blocks(inode, i_size_read(inode))) {
+       if (!truncate_blocks(inode, i_size_read(inode), true)) {
                inode->i_mtime = inode->i_ctime = CURRENT_TIME;
                mark_inode_dirty(inode);
        }
@@ -533,7 +549,7 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr)
 
        if ((attr->ia_valid & ATTR_SIZE) &&
                        attr->ia_size != i_size_read(inode)) {
-               err = f2fs_convert_inline_data(inode, attr->ia_size);
+               err = f2fs_convert_inline_data(inode, attr->ia_size, NULL);
                if (err)
                        return err;
 
@@ -622,7 +638,7 @@ static int punch_hole(struct inode *inode, loff_t offset, loff_t len)
        loff_t off_start, off_end;
        int ret = 0;
 
-       ret = f2fs_convert_inline_data(inode, MAX_INLINE_DATA + 1);
+       ret = f2fs_convert_inline_data(inode, MAX_INLINE_DATA + 1, NULL);
        if (ret)
                return ret;
 
@@ -678,7 +694,7 @@ static int expand_inode_data(struct inode *inode, loff_t offset,
        if (ret)
                return ret;
 
-       ret = f2fs_convert_inline_data(inode, offset + len);
+       ret = f2fs_convert_inline_data(inode, offset + len, NULL);
        if (ret)
                return ret;
 
index d7947d90ccc3df487919723578bf5f81dde2d8a6..943a31db7cc3679c117716b220a58cce1b50a12d 100644 (file)
@@ -58,7 +58,7 @@ static int gc_thread_func(void *data)
                 * 3. IO subsystem is idle by checking the # of requests in
                 *    bdev's request list.
                 *
-                * Note) We have to avoid triggering GCs too much frequently.
+                * Note) We have to avoid triggering GCs frequently.
                 * Because it is possible that some segments can be
                 * invalidated soon after by user update or deletion.
                 * So, I'd like to wait some time to collect dirty segments.
@@ -222,7 +222,7 @@ static unsigned int get_cb_cost(struct f2fs_sb_info *sbi, unsigned int segno)
 
        u = (vblocks * 100) >> sbi->log_blocks_per_seg;
 
-       /* Handle if the system time is changed by user */
+       /* Handle if the system time has changed by the user */
        if (mtime < sit_i->min_mtime)
                sit_i->min_mtime = mtime;
        if (mtime > sit_i->max_mtime)
@@ -593,7 +593,7 @@ next_step:
 
                if (phase == 2) {
                        inode = f2fs_iget(sb, dni.ino);
-                       if (IS_ERR(inode))
+                       if (IS_ERR(inode) || is_bad_inode(inode))
                                continue;
 
                        start_bidx = start_bidx_of_node(nofs, F2FS_I(inode));
@@ -693,7 +693,7 @@ int f2fs_gc(struct f2fs_sb_info *sbi)
 gc_more:
        if (unlikely(!(sbi->sb->s_flags & MS_ACTIVE)))
                goto stop;
-       if (unlikely(is_set_ckpt_flags(F2FS_CKPT(sbi), CP_ERROR_FLAG)))
+       if (unlikely(f2fs_cp_error(sbi)))
                goto stop;
 
        if (gc_type == BG_GC && has_not_enough_free_secs(sbi, nfree)) {
index 5d5eb6047bf467a4c27fba131acdf7ffbff4ab20..16f0b2b22999ffbc3c8ed46afe0e042d4748ea14 100644 (file)
@@ -91,7 +91,7 @@ static inline bool has_enough_invalid_blocks(struct f2fs_sb_info *sbi)
        block_t invalid_user_blocks = sbi->user_block_count -
                                        written_block_count(sbi);
        /*
-        * Background GC is triggered with the following condition.
+        * Background GC is triggered with the following conditions.
         * 1. There are a number of invalid blocks.
         * 2. There is not enough free space.
         */
index 948d17bf7281f6c9c32cf1e889dc844e57fbe893..a844fcfb9a8dcc70859e44c8933c465d9be36fb9 100644 (file)
@@ -42,7 +42,8 @@ static void TEA_transform(unsigned int buf[4], unsigned int const in[])
        buf[1] += b1;
 }
 
-static void str2hashbuf(const char *msg, size_t len, unsigned int *buf, int num)
+static void str2hashbuf(const unsigned char *msg, size_t len,
+                               unsigned int *buf, int num)
 {
        unsigned pad, val;
        int i;
@@ -73,9 +74,9 @@ f2fs_hash_t f2fs_dentry_hash(const struct qstr *name_info)
 {
        __u32 hash;
        f2fs_hash_t f2fs_hash;
-       const char *p;
+       const unsigned char *p;
        __u32 in[8], buf[4];
-       const char *name = name_info->name;
+       const unsigned char *name = name_info->name;
        size_t len = name_info->len;
 
        if ((len <= 2) && (name[0] == '.') &&
index 5beeccef9ae1bf968c29f688e4b70664e6f8ce82..3e8ecdf3742b18d72eba2e9c780f2c6e8d215c5e 100644 (file)
@@ -68,7 +68,7 @@ out:
 
 static int __f2fs_convert_inline_data(struct inode *inode, struct page *page)
 {
-       int err;
+       int err = 0;
        struct page *ipage;
        struct dnode_of_data dn;
        void *src_addr, *dst_addr;
@@ -86,6 +86,10 @@ static int __f2fs_convert_inline_data(struct inode *inode, struct page *page)
                goto out;
        }
 
+       /* someone else converted inline_data already */
+       if (!f2fs_has_inline_data(inode))
+               goto out;
+
        /*
         * i_addr[0] is not used for inline data,
         * so reserving new block will not destroy inline data
@@ -124,9 +128,10 @@ out:
        return err;
 }
 
-int f2fs_convert_inline_data(struct inode *inode, pgoff_t to_size)
+int f2fs_convert_inline_data(struct inode *inode, pgoff_t to_size,
+                                               struct page *page)
 {
-       struct page *page;
+       struct page *new_page = page;
        int err;
 
        if (!f2fs_has_inline_data(inode))
@@ -134,17 +139,20 @@ int f2fs_convert_inline_data(struct inode *inode, pgoff_t to_size)
        else if (to_size <= MAX_INLINE_DATA)
                return 0;
 
-       page = grab_cache_page(inode->i_mapping, 0);
-       if (!page)
-               return -ENOMEM;
+       if (!page || page->index != 0) {
+               new_page = grab_cache_page(inode->i_mapping, 0);
+               if (!new_page)
+                       return -ENOMEM;
+       }
 
-       err = __f2fs_convert_inline_data(inode, page);
-       f2fs_put_page(page, 1);
+       err = __f2fs_convert_inline_data(inode, new_page);
+       if (!page || page->index != 0)
+               f2fs_put_page(new_page, 1);
        return err;
 }
 
 int f2fs_write_inline_data(struct inode *inode,
-                          struct page *page, unsigned size)
+                               struct page *page, unsigned size)
 {
        void *src_addr, *dst_addr;
        struct page *ipage;
@@ -199,7 +207,7 @@ void truncate_inline_data(struct inode *inode, u64 from)
        f2fs_put_page(ipage, 1);
 }
 
-int recover_inline_data(struct inode *inode, struct page *npage)
+bool recover_inline_data(struct inode *inode, struct page *npage)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
        struct f2fs_inode *ri = NULL;
@@ -218,7 +226,7 @@ int recover_inline_data(struct inode *inode, struct page *npage)
                ri = F2FS_INODE(npage);
 
        if (f2fs_has_inline_data(inode) &&
-                       ri && ri->i_inline & F2FS_INLINE_DATA) {
+                       ri && (ri->i_inline & F2FS_INLINE_DATA)) {
 process_inline:
                ipage = get_node_page(sbi, inode->i_ino);
                f2fs_bug_on(IS_ERR(ipage));
@@ -230,7 +238,7 @@ process_inline:
                memcpy(dst_addr, src_addr, MAX_INLINE_DATA);
                update_inode(inode, ipage);
                f2fs_put_page(ipage, 1);
-               return -1;
+               return true;
        }
 
        if (f2fs_has_inline_data(inode)) {
@@ -242,10 +250,10 @@ process_inline:
                clear_inode_flag(F2FS_I(inode), FI_INLINE_DATA);
                update_inode(inode, ipage);
                f2fs_put_page(ipage, 1);
-       } else if (ri && ri->i_inline & F2FS_INLINE_DATA) {
-               truncate_blocks(inode, 0);
+       } else if (ri && (ri->i_inline & F2FS_INLINE_DATA)) {
+               truncate_blocks(inode, 0, false);
                set_inode_flag(F2FS_I(inode), FI_INLINE_DATA);
                goto process_inline;
        }
-       return 0;
+       return false;
 }
index 27b03776ffd21b8377dd645ba15591c1e783c19e..ee103fd7283c4e26acb39abf80fdaacdafea116f 100644 (file)
@@ -134,9 +134,7 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
        return 0;
 out:
        clear_nlink(inode);
-       unlock_new_inode(inode);
-       make_bad_inode(inode);
-       iput(inode);
+       iget_failed(inode);
        alloc_nid_failed(sbi, ino);
        return err;
 }
@@ -229,7 +227,7 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
        f2fs_delete_entry(de, page, inode);
        f2fs_unlock_op(sbi);
 
-       /* In order to evict this inode,  we set it dirty */
+       /* In order to evict this inode, we set it dirty */
        mark_inode_dirty(inode);
 fail:
        trace_f2fs_unlink_exit(inode, err);
@@ -267,9 +265,7 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
        return err;
 out:
        clear_nlink(inode);
-       unlock_new_inode(inode);
-       make_bad_inode(inode);
-       iput(inode);
+       iget_failed(inode);
        alloc_nid_failed(sbi, inode->i_ino);
        return err;
 }
@@ -308,9 +304,7 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 out_fail:
        clear_inode_flag(F2FS_I(inode), FI_INC_LINK);
        clear_nlink(inode);
-       unlock_new_inode(inode);
-       make_bad_inode(inode);
-       iput(inode);
+       iget_failed(inode);
        alloc_nid_failed(sbi, inode->i_ino);
        return err;
 }
@@ -354,9 +348,7 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry,
        return 0;
 out:
        clear_nlink(inode);
-       unlock_new_inode(inode);
-       make_bad_inode(inode);
-       iput(inode);
+       iget_failed(inode);
        alloc_nid_failed(sbi, inode->i_ino);
        return err;
 }
@@ -688,9 +680,7 @@ release_out:
 out:
        f2fs_unlock_op(sbi);
        clear_nlink(inode);
-       unlock_new_inode(inode);
-       make_bad_inode(inode);
-       iput(inode);
+       iget_failed(inode);
        alloc_nid_failed(sbi, inode->i_ino);
        return err;
 }
@@ -704,7 +694,6 @@ const struct inode_operations f2fs_dir_inode_operations = {
        .mkdir          = f2fs_mkdir,
        .rmdir          = f2fs_rmdir,
        .mknod          = f2fs_mknod,
-       .rename         = f2fs_rename,
        .rename2        = f2fs_rename2,
        .tmpfile        = f2fs_tmpfile,
        .getattr        = f2fs_getattr,
index d3d90d2846313d546c1328145d48a2013645f3dd..45378196e19acbab2b2d3150a5158681eaa4a045 100644 (file)
@@ -237,7 +237,7 @@ retry:
                        nat_get_blkaddr(e) != NULL_ADDR &&
                        new_blkaddr == NEW_ADDR);
 
-       /* increament version no as node is removed */
+       /* increment version no as node is removed */
        if (nat_get_blkaddr(e) != NEW_ADDR && new_blkaddr == NULL_ADDR) {
                unsigned char version = nat_get_version(e);
                nat_set_version(e, inc_node_version(version));
@@ -274,7 +274,7 @@ int try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink)
 }
 
 /*
- * This function returns always success
+ * This function always returns success
  */
 void get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni)
 {
@@ -650,7 +650,7 @@ static int truncate_partial_nodes(struct dnode_of_data *dn,
 
        /* get indirect nodes in the path */
        for (i = 0; i < idx + 1; i++) {
-               /* refernece count'll be increased */
+               /* reference count'll be increased */
                pages[i] = get_node_page(sbi, nid[i]);
                if (IS_ERR(pages[i])) {
                        err = PTR_ERR(pages[i]);
@@ -823,22 +823,26 @@ int truncate_xattr_node(struct inode *inode, struct page *page)
  */
 void remove_inode_page(struct inode *inode)
 {
-       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
-       struct page *page;
-       nid_t ino = inode->i_ino;
        struct dnode_of_data dn;
 
-       page = get_node_page(sbi, ino);
-       if (IS_ERR(page))
+       set_new_dnode(&dn, inode, NULL, NULL, inode->i_ino);
+       if (get_dnode_of_data(&dn, 0, LOOKUP_NODE))
                return;
 
-       if (truncate_xattr_node(inode, page)) {
-               f2fs_put_page(page, 1);
+       if (truncate_xattr_node(inode, dn.inode_page)) {
+               f2fs_put_dnode(&dn);
                return;
        }
-       /* 0 is possible, after f2fs_new_inode() is failed */
+
+       /* remove potential inline_data blocks */
+       if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
+                               S_ISLNK(inode->i_mode))
+               truncate_data_blocks_range(&dn, 1);
+
+       /* 0 is possible, after f2fs_new_inode() has failed */
        f2fs_bug_on(inode->i_blocks != 0 && inode->i_blocks != 1);
-       set_new_dnode(&dn, inode, page, page, ino);
+
+       /* will put inode & node pages */
        truncate_node(&dn);
 }
 
@@ -1129,8 +1133,11 @@ continue_unlock:
                                set_fsync_mark(page, 0);
                                set_dentry_mark(page, 0);
                        }
-                       NODE_MAPPING(sbi)->a_ops->writepage(page, wbc);
-                       wrote++;
+
+                       if (NODE_MAPPING(sbi)->a_ops->writepage(page, wbc))
+                               unlock_page(page);
+                       else
+                               wrote++;
 
                        if (--wbc->nr_to_write == 0)
                                break;
@@ -1212,6 +1219,8 @@ static int f2fs_write_node_page(struct page *page,
 
        if (unlikely(sbi->por_doing))
                goto redirty_out;
+       if (unlikely(f2fs_cp_error(sbi)))
+               goto redirty_out;
 
        f2fs_wait_on_page_writeback(page, NODE);
 
@@ -1540,15 +1549,6 @@ void alloc_nid_failed(struct f2fs_sb_info *sbi, nid_t nid)
                kmem_cache_free(free_nid_slab, i);
 }
 
-void recover_node_page(struct f2fs_sb_info *sbi, struct page *page,
-               struct f2fs_summary *sum, struct node_info *ni,
-               block_t new_blkaddr)
-{
-       rewrite_node_page(sbi, page, sum, ni->blk_addr, new_blkaddr);
-       set_node_addr(sbi, ni, new_blkaddr, false);
-       clear_node_page_dirty(page);
-}
-
 void recover_inline_xattr(struct inode *inode, struct page *page)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
@@ -1557,40 +1557,33 @@ void recover_inline_xattr(struct inode *inode, struct page *page)
        struct page *ipage;
        struct f2fs_inode *ri;
 
-       if (!f2fs_has_inline_xattr(inode))
-               return;
-
-       if (!IS_INODE(page))
-               return;
-
-       ri = F2FS_INODE(page);
-       if (!(ri->i_inline & F2FS_INLINE_XATTR))
-               return;
-
        ipage = get_node_page(sbi, inode->i_ino);
        f2fs_bug_on(IS_ERR(ipage));
 
+       ri = F2FS_INODE(page);
+       if (!(ri->i_inline & F2FS_INLINE_XATTR)) {
+               clear_inode_flag(F2FS_I(inode), FI_INLINE_XATTR);
+               goto update_inode;
+       }
+
        dst_addr = inline_xattr_addr(ipage);
        src_addr = inline_xattr_addr(page);
        inline_size = inline_xattr_size(inode);
 
        f2fs_wait_on_page_writeback(ipage, NODE);
        memcpy(dst_addr, src_addr, inline_size);
-
+update_inode:
        update_inode(inode, ipage);
        f2fs_put_page(ipage, 1);
 }
 
-bool recover_xattr_data(struct inode *inode, struct page *page, block_t blkaddr)
+void recover_xattr_data(struct inode *inode, struct page *page, block_t blkaddr)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
        nid_t prev_xnid = F2FS_I(inode)->i_xattr_nid;
        nid_t new_xnid = nid_of_node(page);
        struct node_info ni;
 
-       if (!f2fs_has_xattr_block(ofs_of_node(page)))
-               return false;
-
        /* 1: invalidate the previous xattr nid */
        if (!prev_xnid)
                goto recover_xnid;
@@ -1618,7 +1611,6 @@ recover_xnid:
        set_node_addr(sbi, &ni, blkaddr, false);
 
        update_inode_page(inode);
-       return true;
 }
 
 int recover_inode_page(struct f2fs_sb_info *sbi, struct page *page)
@@ -1637,7 +1629,7 @@ int recover_inode_page(struct f2fs_sb_info *sbi, struct page *page)
        if (!ipage)
                return -ENOMEM;
 
-       /* Should not use this inode  from free nid list */
+       /* Should not use this inode from free nid list */
        remove_free_nid(NM_I(sbi), ino);
 
        SetPageUptodate(ipage);
@@ -1651,6 +1643,7 @@ int recover_inode_page(struct f2fs_sb_info *sbi, struct page *page)
        dst->i_blocks = cpu_to_le64(1);
        dst->i_links = cpu_to_le32(1);
        dst->i_xattr_nid = 0;
+       dst->i_inline = src->i_inline & F2FS_INLINE_XATTR;
 
        new_ni = old_ni;
        new_ni.ino = ino;
@@ -1659,13 +1652,14 @@ int recover_inode_page(struct f2fs_sb_info *sbi, struct page *page)
                WARN_ON(1);
        set_node_addr(sbi, &new_ni, NEW_ADDR, false);
        inc_valid_inode_count(sbi);
+       set_page_dirty(ipage);
        f2fs_put_page(ipage, 1);
        return 0;
 }
 
 /*
  * ra_sum_pages() merge contiguous pages into one bio and submit.
- * these pre-readed pages are alloced in bd_inode's mapping tree.
+ * these pre-read pages are allocated in bd_inode's mapping tree.
  */
 static int ra_sum_pages(struct f2fs_sb_info *sbi, struct page **pages,
                                int start, int nrpages)
@@ -1709,7 +1703,7 @@ int restore_node_summary(struct f2fs_sb_info *sbi,
        for (i = 0; !err && i < last_offset; i += nrpages, addr += nrpages) {
                nrpages = min(last_offset - i, bio_blocks);
 
-               /* read ahead node pages */
+               /* readahead node pages */
                nrpages = ra_sum_pages(sbi, pages, addr, nrpages);
                if (!nrpages)
                        return -ENOMEM;
@@ -1967,7 +1961,7 @@ static int init_node_manager(struct f2fs_sb_info *sbi)
        nm_i->max_nid = NAT_ENTRY_PER_BLOCK * nat_blocks;
 
        /* not used nids: 0, node, meta, (and root counted as valid node) */
-       nm_i->available_nids = nm_i->max_nid - 3;
+       nm_i->available_nids = nm_i->max_nid - F2FS_RESERVED_NODE_NUM;
        nm_i->fcnt = 0;
        nm_i->nat_cnt = 0;
        nm_i->ram_thresh = DEF_RAM_THRESHOLD;
index fe1c6d921ba2fb535464d031d5822877e6eeccbd..756c41cd25829f789931df79f14a95bebcba5431 100644 (file)
@@ -62,8 +62,10 @@ static int recover_dentry(struct page *ipage, struct inode *inode)
        }
 retry:
        de = f2fs_find_entry(dir, &name, &page);
-       if (de && inode->i_ino == le32_to_cpu(de->ino))
+       if (de && inode->i_ino == le32_to_cpu(de->ino)) {
+               clear_inode_flag(F2FS_I(inode), FI_INC_LINK);
                goto out_unmap_put;
+       }
        if (de) {
                einode = f2fs_iget(inode->i_sb, le32_to_cpu(de->ino));
                if (IS_ERR(einode)) {
@@ -300,14 +302,19 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
        struct node_info ni;
        int err = 0, recovered = 0;
 
-       recover_inline_xattr(inode, page);
-
-       if (recover_inline_data(inode, page))
+       /* step 1: recover xattr */
+       if (IS_INODE(page)) {
+               recover_inline_xattr(inode, page);
+       } else if (f2fs_has_xattr_block(ofs_of_node(page))) {
+               recover_xattr_data(inode, page, blkaddr);
                goto out;
+       }
 
-       if (recover_xattr_data(inode, page, blkaddr))
+       /* step 2: recover inline data */
+       if (recover_inline_data(inode, page))
                goto out;
 
+       /* step 3: recover data indices */
        start = start_bidx_of_node(ofs_of_node(page), fi);
        end = start + ADDRS_PER_PAGE(page, fi);
 
@@ -364,8 +371,6 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
        fill_node_footer(dn.node_page, dn.nid, ni.ino,
                                        ofs_of_node(page), false);
        set_page_dirty(dn.node_page);
-
-       recover_node_page(sbi, dn.node_page, &sum, &ni, blkaddr);
 err:
        f2fs_put_dnode(&dn);
        f2fs_unlock_op(sbi);
@@ -452,6 +457,9 @@ int recover_fsync_data(struct f2fs_sb_info *sbi)
        /* step #1: find fsynced inode numbers */
        sbi->por_doing = true;
 
+       /* prevent checkpoint */
+       mutex_lock(&sbi->cp_mutex);
+
        blkaddr = NEXT_FREE_BLKADDR(sbi, curseg);
 
        err = find_fsync_dnodes(sbi, &inode_list);
@@ -465,7 +473,8 @@ int recover_fsync_data(struct f2fs_sb_info *sbi)
 
        /* step #2: recover data */
        err = recover_data(sbi, &inode_list, CURSEG_WARM_NODE);
-       f2fs_bug_on(!list_empty(&inode_list));
+       if (!err)
+               f2fs_bug_on(!list_empty(&inode_list));
 out:
        destroy_fsync_dnodes(&inode_list);
        kmem_cache_destroy(fsync_entry_slab);
@@ -482,8 +491,13 @@ out:
                /* Flush all the NAT/SIT pages */
                while (get_pages(sbi, F2FS_DIRTY_META))
                        sync_meta_pages(sbi, META, LONG_MAX);
+               set_ckpt_flags(sbi->ckpt, CP_ERROR_FLAG);
+               mutex_unlock(&sbi->cp_mutex);
        } else if (need_writecp) {
+               mutex_unlock(&sbi->cp_mutex);
                write_checkpoint(sbi, false);
+       } else {
+               mutex_unlock(&sbi->cp_mutex);
        }
        return err;
 }
index 0dfeebae2a50f1d8ff4b7a33e19a25fb32c2e834..0aa337cd5bba85703bdcecde7fe0a35de76bf121 100644 (file)
@@ -62,7 +62,7 @@ static inline unsigned long __reverse_ffs(unsigned long word)
 }
 
 /*
- * __find_rev_next(_zero)_bit is copied from lib/find_next_bit.c becasue
+ * __find_rev_next(_zero)_bit is copied from lib/find_next_bit.c because
  * f2fs_set_bit makes MSB and LSB reversed in a byte.
  * Example:
  *                             LSB <--> MSB
@@ -808,7 +808,7 @@ static void __refresh_next_blkoff(struct f2fs_sb_info *sbi,
 }
 
 /*
- * This function always allocates a used segment (from dirty seglist) by SSR
+ * This function always allocates a used segment(from dirty seglist) by SSR
  * manner, so it should recover the existing segment information of valid blocks
  */
 static void change_curseg(struct f2fs_sb_info *sbi, int type, bool reuse)
@@ -1103,55 +1103,6 @@ void recover_data_page(struct f2fs_sb_info *sbi,
        mutex_unlock(&curseg->curseg_mutex);
 }
 
-void rewrite_node_page(struct f2fs_sb_info *sbi,
-                       struct page *page, struct f2fs_summary *sum,
-                       block_t old_blkaddr, block_t new_blkaddr)
-{
-       struct sit_info *sit_i = SIT_I(sbi);
-       int type = CURSEG_WARM_NODE;
-       struct curseg_info *curseg;
-       unsigned int segno, old_cursegno;
-       block_t next_blkaddr = next_blkaddr_of_node(page);
-       unsigned int next_segno = GET_SEGNO(sbi, next_blkaddr);
-       struct f2fs_io_info fio = {
-               .type = NODE,
-               .rw = WRITE_SYNC,
-       };
-
-       curseg = CURSEG_I(sbi, type);
-
-       mutex_lock(&curseg->curseg_mutex);
-       mutex_lock(&sit_i->sentry_lock);
-
-       segno = GET_SEGNO(sbi, new_blkaddr);
-       old_cursegno = curseg->segno;
-
-       /* change the current segment */
-       if (segno != curseg->segno) {
-               curseg->next_segno = segno;
-               change_curseg(sbi, type, true);
-       }
-       curseg->next_blkoff = GET_BLKOFF_FROM_SEG0(sbi, new_blkaddr);
-       __add_sum_entry(sbi, type, sum);
-
-       /* change the current log to the next block addr in advance */
-       if (next_segno != segno) {
-               curseg->next_segno = next_segno;
-               change_curseg(sbi, type, true);
-       }
-       curseg->next_blkoff = GET_BLKOFF_FROM_SEG0(sbi, next_blkaddr);
-
-       /* rewrite node page */
-       set_page_writeback(page);
-       f2fs_submit_page_mbio(sbi, page, new_blkaddr, &fio);
-       f2fs_submit_merged_bio(sbi, NODE, WRITE);
-       refresh_sit_entry(sbi, old_blkaddr, new_blkaddr);
-       locate_dirty_segment(sbi, old_cursegno);
-
-       mutex_unlock(&sit_i->sentry_lock);
-       mutex_unlock(&curseg->curseg_mutex);
-}
-
 static inline bool is_merged_page(struct f2fs_sb_info *sbi,
                                        struct page *page, enum page_type type)
 {
index 55973f7b0330be844e17c0f02b7c02d661ca8c3e..ff483257283b8789968473b4beda6c2ddbaff43b 100644 (file)
@@ -549,7 +549,7 @@ static inline void verify_block_addr(struct f2fs_sb_info *sbi, block_t blk_addr)
 }
 
 /*
- * Summary block is always treated as invalid block
+ * Summary block is always treated as an invalid block
  */
 static inline void check_block_count(struct f2fs_sb_info *sbi,
                int segno, struct f2fs_sit_entry *raw_sit)
index 657582fc7601ad27f81ef034a6f5e55cf46abc1e..41bdf511003deb6978cf852203906840167f90b6 100644 (file)
@@ -432,9 +432,15 @@ static void f2fs_put_super(struct super_block *sb)
        stop_gc_thread(sbi);
 
        /* We don't need to do checkpoint when it's clean */
-       if (sbi->s_dirty && get_pages(sbi, F2FS_DIRTY_NODES))
+       if (sbi->s_dirty)
                write_checkpoint(sbi, true);
 
+       /*
+        * normally superblock is clean, so we need to release this.
+        * In addition, EIO will skip do checkpoint, we need this as well.
+        */
+       release_dirty_inode(sbi);
+
        iput(sbi->node_inode);
        iput(sbi->meta_inode);
 
@@ -457,9 +463,6 @@ int f2fs_sync_fs(struct super_block *sb, int sync)
 
        trace_f2fs_sync_fs(sb, sync);
 
-       if (!sbi->s_dirty && !get_pages(sbi, F2FS_DIRTY_NODES))
-               return 0;
-
        if (sync) {
                mutex_lock(&sbi->gc_mutex);
                write_checkpoint(sbi, false);
@@ -505,8 +508,8 @@ static int f2fs_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_bfree = buf->f_blocks - valid_user_blocks(sbi) - ovp_count;
        buf->f_bavail = user_block_count - valid_user_blocks(sbi);
 
-       buf->f_files = sbi->total_node_count;
-       buf->f_ffree = sbi->total_node_count - valid_inode_count(sbi);
+       buf->f_files = sbi->total_node_count - F2FS_RESERVED_NODE_NUM;
+       buf->f_ffree = buf->f_files - valid_inode_count(sbi);
 
        buf->f_namelen = F2FS_NAME_LEN;
        buf->f_fsid.val[0] = (u32)id;
@@ -663,7 +666,7 @@ restore_gc:
        if (need_restart_gc) {
                if (start_gc_thread(sbi))
                        f2fs_msg(sbi->sb, KERN_WARNING,
-                               "background gc thread is stop");
+                               "background gc thread has stopped");
        } else if (need_stop_gc) {
                stop_gc_thread(sbi);
        }
@@ -812,7 +815,7 @@ static int sanity_check_ckpt(struct f2fs_sb_info *sbi)
        if (unlikely(fsmeta >= total))
                return 1;
 
-       if (unlikely(is_set_ckpt_flags(ckpt, CP_ERROR_FLAG))) {
+       if (unlikely(f2fs_cp_error(sbi))) {
                f2fs_msg(sbi->sb, KERN_ERR, "A bug case: need to run fsck");
                return 1;
        }
@@ -899,8 +902,10 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
        struct buffer_head *raw_super_buf;
        struct inode *root;
        long err = -EINVAL;
+       bool retry = true;
        int i;
 
+try_onemore:
        /* allocate memory for f2fs-specific super block info */
        sbi = kzalloc(sizeof(struct f2fs_sb_info), GFP_KERNEL);
        if (!sbi)
@@ -1080,9 +1085,11 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
        /* recover fsynced data */
        if (!test_opt(sbi, DISABLE_ROLL_FORWARD)) {
                err = recover_fsync_data(sbi);
-               if (err)
+               if (err) {
                        f2fs_msg(sb, KERN_ERR,
                                "Cannot recover all fsync data errno=%ld", err);
+                       goto free_kobj;
+               }
        }
 
        /*
@@ -1123,6 +1130,13 @@ free_sb_buf:
        brelse(raw_super_buf);
 free_sbi:
        kfree(sbi);
+
+       /* give only one another chance */
+       if (retry) {
+               retry = 0;
+               shrink_dcache_sb(sb);
+               goto try_onemore;
+       }
        return err;
 }
 
index 8bea941ee309607647cbc7a8c1282e0419dcef12..728a5dc3dc1654190e9709ce1f19fbc87a39d843 100644 (file)
@@ -528,7 +528,7 @@ static int __f2fs_setxattr(struct inode *inode, int index,
                int free;
                /*
                 * If value is NULL, it is remove operation.
-                * In case of update operation, we caculate free.
+                * In case of update operation, we calculate free.
                 */
                free = MIN_OFFSET(inode) - ((char *)last - (char *)base_addr);
                if (found)
index 4556ce1af5b04f5a4f0cd0b4e1ae0515435a1857..5ddaf8625d3b7a1ab3d0128a91dbd3b84b8b9b0b 100644 (file)
@@ -61,7 +61,7 @@ static void isofs_put_super(struct super_block *sb)
        return;
 }
 
-static int isofs_read_inode(struct inode *);
+static int isofs_read_inode(struct inode *, int relocated);
 static int isofs_statfs (struct dentry *, struct kstatfs *);
 
 static struct kmem_cache *isofs_inode_cachep;
@@ -1259,7 +1259,7 @@ out_toomany:
        goto out;
 }
 
-static int isofs_read_inode(struct inode *inode)
+static int isofs_read_inode(struct inode *inode, int relocated)
 {
        struct super_block *sb = inode->i_sb;
        struct isofs_sb_info *sbi = ISOFS_SB(sb);
@@ -1404,7 +1404,7 @@ static int isofs_read_inode(struct inode *inode)
         */
 
        if (!high_sierra) {
-               parse_rock_ridge_inode(de, inode);
+               parse_rock_ridge_inode(de, inode, relocated);
                /* if we want uid/gid set, override the rock ridge setting */
                if (sbi->s_uid_set)
                        inode->i_uid = sbi->s_uid;
@@ -1483,9 +1483,10 @@ static int isofs_iget5_set(struct inode *ino, void *data)
  * offset that point to the underlying meta-data for the inode.  The
  * code below is otherwise similar to the iget() code in
  * include/linux/fs.h */
-struct inode *isofs_iget(struct super_block *sb,
-                        unsigned long block,
-                        unsigned long offset)
+struct inode *__isofs_iget(struct super_block *sb,
+                          unsigned long block,
+                          unsigned long offset,
+                          int relocated)
 {
        unsigned long hashval;
        struct inode *inode;
@@ -1507,7 +1508,7 @@ struct inode *isofs_iget(struct super_block *sb,
                return ERR_PTR(-ENOMEM);
 
        if (inode->i_state & I_NEW) {
-               ret = isofs_read_inode(inode);
+               ret = isofs_read_inode(inode, relocated);
                if (ret < 0) {
                        iget_failed(inode);
                        inode = ERR_PTR(ret);
index 99167238518d61a30c4a5e6bfc838291d6206a5d..0ac4c1f73fbd6c2616e04ad6310995426c03da68 100644 (file)
@@ -107,7 +107,7 @@ extern int iso_date(char *, int);
 
 struct inode;          /* To make gcc happy */
 
-extern int parse_rock_ridge_inode(struct iso_directory_record *, struct inode *);
+extern int parse_rock_ridge_inode(struct iso_directory_record *, struct inode *, int relocated);
 extern int get_rock_ridge_filename(struct iso_directory_record *, char *, struct inode *);
 extern int isofs_name_translate(struct iso_directory_record *, char *, struct inode *);
 
@@ -118,9 +118,24 @@ extern struct dentry *isofs_lookup(struct inode *, struct dentry *, unsigned int
 extern struct buffer_head *isofs_bread(struct inode *, sector_t);
 extern int isofs_get_blocks(struct inode *, sector_t, struct buffer_head **, unsigned long);
 
-extern struct inode *isofs_iget(struct super_block *sb,
-                                unsigned long block,
-                                unsigned long offset);
+struct inode *__isofs_iget(struct super_block *sb,
+                          unsigned long block,
+                          unsigned long offset,
+                          int relocated);
+
+static inline struct inode *isofs_iget(struct super_block *sb,
+                                      unsigned long block,
+                                      unsigned long offset)
+{
+       return __isofs_iget(sb, block, offset, 0);
+}
+
+static inline struct inode *isofs_iget_reloc(struct super_block *sb,
+                                            unsigned long block,
+                                            unsigned long offset)
+{
+       return __isofs_iget(sb, block, offset, 1);
+}
 
 /* Because the inode number is no longer relevant to finding the
  * underlying meta-data for an inode, we are free to choose a more
index c0bf42472e408fd16911cee33f3d9079943aa46a..f488bbae541ac8d5db4eb7e963c33452ebb3e937 100644 (file)
@@ -288,12 +288,16 @@ eio:
        goto out;
 }
 
+#define RR_REGARD_XA 1
+#define RR_RELOC_DE 2
+
 static int
 parse_rock_ridge_inode_internal(struct iso_directory_record *de,
-                               struct inode *inode, int regard_xa)
+                               struct inode *inode, int flags)
 {
        int symlink_len = 0;
        int cnt, sig;
+       unsigned int reloc_block;
        struct inode *reloc;
        struct rock_ridge *rr;
        int rootflag;
@@ -305,7 +309,7 @@ parse_rock_ridge_inode_internal(struct iso_directory_record *de,
 
        init_rock_state(&rs, inode);
        setup_rock_ridge(de, inode, &rs);
-       if (regard_xa) {
+       if (flags & RR_REGARD_XA) {
                rs.chr += 14;
                rs.len -= 14;
                if (rs.len < 0)
@@ -485,12 +489,22 @@ repeat:
                                        "relocated directory\n");
                        goto out;
                case SIG('C', 'L'):
-                       ISOFS_I(inode)->i_first_extent =
-                           isonum_733(rr->u.CL.location);
-                       reloc =
-                           isofs_iget(inode->i_sb,
-                                      ISOFS_I(inode)->i_first_extent,
-                                      0);
+                       if (flags & RR_RELOC_DE) {
+                               printk(KERN_ERR
+                                      "ISOFS: Recursive directory relocation "
+                                      "is not supported\n");
+                               goto eio;
+                       }
+                       reloc_block = isonum_733(rr->u.CL.location);
+                       if (reloc_block == ISOFS_I(inode)->i_iget5_block &&
+                           ISOFS_I(inode)->i_iget5_offset == 0) {
+                               printk(KERN_ERR
+                                      "ISOFS: Directory relocation points to "
+                                      "itself\n");
+                               goto eio;
+                       }
+                       ISOFS_I(inode)->i_first_extent = reloc_block;
+                       reloc = isofs_iget_reloc(inode->i_sb, reloc_block, 0);
                        if (IS_ERR(reloc)) {
                                ret = PTR_ERR(reloc);
                                goto out;
@@ -637,9 +651,11 @@ static char *get_symlink_chunk(char *rpnt, struct rock_ridge *rr, char *plimit)
        return rpnt;
 }
 
-int parse_rock_ridge_inode(struct iso_directory_record *de, struct inode *inode)
+int parse_rock_ridge_inode(struct iso_directory_record *de, struct inode *inode,
+                          int relocated)
 {
-       int result = parse_rock_ridge_inode_internal(de, inode, 0);
+       int flags = relocated ? RR_RELOC_DE : 0;
+       int result = parse_rock_ridge_inode_internal(de, inode, flags);
 
        /*
         * if rockridge flag was reset and we didn't look for attributes
@@ -647,7 +663,8 @@ int parse_rock_ridge_inode(struct iso_directory_record *de, struct inode *inode)
         */
        if ((ISOFS_SB(inode->i_sb)->s_rock_offset == -1)
            && (ISOFS_SB(inode->i_sb)->s_rock == 2)) {
-               result = parse_rock_ridge_inode_internal(de, inode, 14);
+               result = parse_rock_ridge_inode_internal(de, inode,
+                                                        flags | RR_REGARD_XA);
        }
        return result;
 }
index 6fac743498565746bfb6dd5f29e0abacb48a0865..b73e0215baa7ceeb0dbfd3a77c79d5d498231e60 100644 (file)
@@ -97,7 +97,7 @@ static void jbd2_commit_block_csum_set(journal_t *j, struct buffer_head *bh)
        struct commit_header *h;
        __u32 csum;
 
-       if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2))
+       if (!jbd2_journal_has_csum_v2or3(j))
                return;
 
        h = (struct commit_header *)(bh->b_data);
@@ -313,11 +313,11 @@ static __u32 jbd2_checksum_data(__u32 crc32_sum, struct buffer_head *bh)
        return checksum;
 }
 
-static void write_tag_block(int tag_bytes, journal_block_tag_t *tag,
+static void write_tag_block(journal_t *j, journal_block_tag_t *tag,
                                   unsigned long long block)
 {
        tag->t_blocknr = cpu_to_be32(block & (u32)~0);
-       if (tag_bytes > JBD2_TAG_SIZE32)
+       if (JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_64BIT))
                tag->t_blocknr_high = cpu_to_be32((block >> 31) >> 1);
 }
 
@@ -327,7 +327,7 @@ static void jbd2_descr_block_csum_set(journal_t *j,
        struct jbd2_journal_block_tail *tail;
        __u32 csum;
 
-       if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2))
+       if (!jbd2_journal_has_csum_v2or3(j))
                return;
 
        tail = (struct jbd2_journal_block_tail *)(bh->b_data + j->j_blocksize -
@@ -340,12 +340,13 @@ static void jbd2_descr_block_csum_set(journal_t *j,
 static void jbd2_block_tag_csum_set(journal_t *j, journal_block_tag_t *tag,
                                    struct buffer_head *bh, __u32 sequence)
 {
+       journal_block_tag3_t *tag3 = (journal_block_tag3_t *)tag;
        struct page *page = bh->b_page;
        __u8 *addr;
        __u32 csum32;
        __be32 seq;
 
-       if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2))
+       if (!jbd2_journal_has_csum_v2or3(j))
                return;
 
        seq = cpu_to_be32(sequence);
@@ -355,8 +356,10 @@ static void jbd2_block_tag_csum_set(journal_t *j, journal_block_tag_t *tag,
                             bh->b_size);
        kunmap_atomic(addr);
 
-       /* We only have space to store the lower 16 bits of the crc32c. */
-       tag->t_checksum = cpu_to_be16(csum32);
+       if (JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V3))
+               tag3->t_checksum = cpu_to_be32(csum32);
+       else
+               tag->t_checksum = cpu_to_be16(csum32);
 }
 /*
  * jbd2_journal_commit_transaction
@@ -396,7 +399,7 @@ void jbd2_journal_commit_transaction(journal_t *journal)
        LIST_HEAD(io_bufs);
        LIST_HEAD(log_bufs);
 
-       if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2))
+       if (jbd2_journal_has_csum_v2or3(journal))
                csum_size = sizeof(struct jbd2_journal_block_tail);
 
        /*
@@ -690,7 +693,7 @@ void jbd2_journal_commit_transaction(journal_t *journal)
                        tag_flag |= JBD2_FLAG_SAME_UUID;
 
                tag = (journal_block_tag_t *) tagp;
-               write_tag_block(tag_bytes, tag, jh2bh(jh)->b_blocknr);
+               write_tag_block(journal, tag, jh2bh(jh)->b_blocknr);
                tag->t_flags = cpu_to_be16(tag_flag);
                jbd2_block_tag_csum_set(journal, tag, wbuf[bufs],
                                        commit_transaction->t_tid);
index 67b8e303946ceaa79a0fd0d39ecd8ca428b67f1f..19d74d86d99cc630aec2c0ca8f7bf4ef619e3aa3 100644 (file)
@@ -124,7 +124,7 @@ EXPORT_SYMBOL(__jbd2_debug);
 /* Checksumming functions */
 static int jbd2_verify_csum_type(journal_t *j, journal_superblock_t *sb)
 {
-       if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2))
+       if (!jbd2_journal_has_csum_v2or3(j))
                return 1;
 
        return sb->s_checksum_type == JBD2_CRC32C_CHKSUM;
@@ -145,7 +145,7 @@ static __be32 jbd2_superblock_csum(journal_t *j, journal_superblock_t *sb)
 
 static int jbd2_superblock_csum_verify(journal_t *j, journal_superblock_t *sb)
 {
-       if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2))
+       if (!jbd2_journal_has_csum_v2or3(j))
                return 1;
 
        return sb->s_checksum == jbd2_superblock_csum(j, sb);
@@ -153,7 +153,7 @@ static int jbd2_superblock_csum_verify(journal_t *j, journal_superblock_t *sb)
 
 static void jbd2_superblock_csum_set(journal_t *j, journal_superblock_t *sb)
 {
-       if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2))
+       if (!jbd2_journal_has_csum_v2or3(j))
                return;
 
        sb->s_checksum = jbd2_superblock_csum(j, sb);
@@ -1522,21 +1522,29 @@ static int journal_get_superblock(journal_t *journal)
                goto out;
        }
 
-       if (JBD2_HAS_COMPAT_FEATURE(journal, JBD2_FEATURE_COMPAT_CHECKSUM) &&
-           JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2)) {
+       if (jbd2_journal_has_csum_v2or3(journal) &&
+           JBD2_HAS_COMPAT_FEATURE(journal, JBD2_FEATURE_COMPAT_CHECKSUM)) {
                /* Can't have checksum v1 and v2 on at the same time! */
                printk(KERN_ERR "JBD2: Can't enable checksumming v1 and v2 "
                       "at the same time!\n");
                goto out;
        }
 
+       if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2) &&
+           JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V3)) {
+               /* Can't have checksum v2 and v3 at the same time! */
+               printk(KERN_ERR "JBD2: Can't enable checksumming v2 and v3 "
+                      "at the same time!\n");
+               goto out;
+       }
+
        if (!jbd2_verify_csum_type(journal, sb)) {
                printk(KERN_ERR "JBD2: Unknown checksum type\n");
                goto out;
        }
 
        /* Load the checksum driver */
-       if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2)) {
+       if (jbd2_journal_has_csum_v2or3(journal)) {
                journal->j_chksum_driver = crypto_alloc_shash("crc32c", 0, 0);
                if (IS_ERR(journal->j_chksum_driver)) {
                        printk(KERN_ERR "JBD2: Cannot load crc32c driver.\n");
@@ -1553,7 +1561,7 @@ static int journal_get_superblock(journal_t *journal)
        }
 
        /* Precompute checksum seed for all metadata */
-       if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2))
+       if (jbd2_journal_has_csum_v2or3(journal))
                journal->j_csum_seed = jbd2_chksum(journal, ~0, sb->s_uuid,
                                                   sizeof(sb->s_uuid));
 
@@ -1813,8 +1821,14 @@ int jbd2_journal_set_features (journal_t *journal, unsigned long compat,
        if (!jbd2_journal_check_available_features(journal, compat, ro, incompat))
                return 0;
 
-       /* Asking for checksumming v2 and v1?  Only give them v2. */
-       if (incompat & JBD2_FEATURE_INCOMPAT_CSUM_V2 &&
+       /* If enabling v2 checksums, turn on v3 instead */
+       if (incompat & JBD2_FEATURE_INCOMPAT_CSUM_V2) {
+               incompat &= ~JBD2_FEATURE_INCOMPAT_CSUM_V2;
+               incompat |= JBD2_FEATURE_INCOMPAT_CSUM_V3;
+       }
+
+       /* Asking for checksumming v3 and v1?  Only give them v3. */
+       if (incompat & JBD2_FEATURE_INCOMPAT_CSUM_V3 &&
            compat & JBD2_FEATURE_COMPAT_CHECKSUM)
                compat &= ~JBD2_FEATURE_COMPAT_CHECKSUM;
 
@@ -1823,8 +1837,8 @@ int jbd2_journal_set_features (journal_t *journal, unsigned long compat,
 
        sb = journal->j_superblock;
 
-       /* If enabling v2 checksums, update superblock */
-       if (INCOMPAT_FEATURE_ON(JBD2_FEATURE_INCOMPAT_CSUM_V2)) {
+       /* If enabling v3 checksums, update superblock */
+       if (INCOMPAT_FEATURE_ON(JBD2_FEATURE_INCOMPAT_CSUM_V3)) {
                sb->s_checksum_type = JBD2_CRC32C_CHKSUM;
                sb->s_feature_compat &=
                        ~cpu_to_be32(JBD2_FEATURE_COMPAT_CHECKSUM);
@@ -1842,8 +1856,7 @@ int jbd2_journal_set_features (journal_t *journal, unsigned long compat,
                }
 
                /* Precompute checksum seed for all metadata */
-               if (JBD2_HAS_INCOMPAT_FEATURE(journal,
-                                             JBD2_FEATURE_INCOMPAT_CSUM_V2))
+               if (jbd2_journal_has_csum_v2or3(journal))
                        journal->j_csum_seed = jbd2_chksum(journal, ~0,
                                                           sb->s_uuid,
                                                           sizeof(sb->s_uuid));
@@ -1852,7 +1865,8 @@ int jbd2_journal_set_features (journal_t *journal, unsigned long compat,
        /* If enabling v1 checksums, downgrade superblock */
        if (COMPAT_FEATURE_ON(JBD2_FEATURE_COMPAT_CHECKSUM))
                sb->s_feature_incompat &=
-                       ~cpu_to_be32(JBD2_FEATURE_INCOMPAT_CSUM_V2);
+                       ~cpu_to_be32(JBD2_FEATURE_INCOMPAT_CSUM_V2 |
+                                    JBD2_FEATURE_INCOMPAT_CSUM_V3);
 
        sb->s_feature_compat    |= cpu_to_be32(compat);
        sb->s_feature_ro_compat |= cpu_to_be32(ro);
@@ -2165,16 +2179,20 @@ int jbd2_journal_blocks_per_page(struct inode *inode)
  */
 size_t journal_tag_bytes(journal_t *journal)
 {
-       journal_block_tag_t tag;
-       size_t x = 0;
+       size_t sz;
+
+       if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V3))
+               return sizeof(journal_block_tag3_t);
+
+       sz = sizeof(journal_block_tag_t);
 
        if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2))
-               x += sizeof(tag.t_checksum);
+               sz += sizeof(__u16);
 
        if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT))
-               return x + JBD2_TAG_SIZE64;
+               return sz;
        else
-               return x + JBD2_TAG_SIZE32;
+               return sz - sizeof(__u32);
 }
 
 /*
index 3b6bb19d60b17abceadec4c38df5d3570c0fcba9..9b329b55ffe3726a611ccf8282190e420d173080 100644 (file)
@@ -181,7 +181,7 @@ static int jbd2_descr_block_csum_verify(journal_t *j,
        __be32 provided;
        __u32 calculated;
 
-       if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2))
+       if (!jbd2_journal_has_csum_v2or3(j))
                return 1;
 
        tail = (struct jbd2_journal_block_tail *)(buf + j->j_blocksize -
@@ -205,7 +205,7 @@ static int count_tags(journal_t *journal, struct buffer_head *bh)
        int                     nr = 0, size = journal->j_blocksize;
        int                     tag_bytes = journal_tag_bytes(journal);
 
-       if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2))
+       if (jbd2_journal_has_csum_v2or3(journal))
                size -= sizeof(struct jbd2_journal_block_tail);
 
        tagp = &bh->b_data[sizeof(journal_header_t)];
@@ -338,10 +338,11 @@ int jbd2_journal_skip_recovery(journal_t *journal)
        return err;
 }
 
-static inline unsigned long long read_tag_block(int tag_bytes, journal_block_tag_t *tag)
+static inline unsigned long long read_tag_block(journal_t *journal,
+                                               journal_block_tag_t *tag)
 {
        unsigned long long block = be32_to_cpu(tag->t_blocknr);
-       if (tag_bytes > JBD2_TAG_SIZE32)
+       if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT))
                block |= (u64)be32_to_cpu(tag->t_blocknr_high) << 32;
        return block;
 }
@@ -384,7 +385,7 @@ static int jbd2_commit_block_csum_verify(journal_t *j, void *buf)
        __be32 provided;
        __u32 calculated;
 
-       if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2))
+       if (!jbd2_journal_has_csum_v2or3(j))
                return 1;
 
        h = buf;
@@ -399,17 +400,21 @@ static int jbd2_commit_block_csum_verify(journal_t *j, void *buf)
 static int jbd2_block_tag_csum_verify(journal_t *j, journal_block_tag_t *tag,
                                      void *buf, __u32 sequence)
 {
+       journal_block_tag3_t *tag3 = (journal_block_tag3_t *)tag;
        __u32 csum32;
        __be32 seq;
 
-       if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2))
+       if (!jbd2_journal_has_csum_v2or3(j))
                return 1;
 
        seq = cpu_to_be32(sequence);
        csum32 = jbd2_chksum(j, j->j_csum_seed, (__u8 *)&seq, sizeof(seq));
        csum32 = jbd2_chksum(j, csum32, buf, j->j_blocksize);
 
-       return tag->t_checksum == cpu_to_be16(csum32);
+       if (JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V3))
+               return tag3->t_checksum == cpu_to_be32(csum32);
+       else
+               return tag->t_checksum == cpu_to_be16(csum32);
 }
 
 static int do_one_pass(journal_t *journal,
@@ -426,6 +431,7 @@ static int do_one_pass(journal_t *journal,
        int                     tag_bytes = journal_tag_bytes(journal);
        __u32                   crc32_sum = ~0; /* Transactional Checksums */
        int                     descr_csum_size = 0;
+       int                     block_error = 0;
 
        /*
         * First thing is to establish what we expect to find in the log
@@ -512,8 +518,7 @@ static int do_one_pass(journal_t *journal,
                switch(blocktype) {
                case JBD2_DESCRIPTOR_BLOCK:
                        /* Verify checksum first */
-                       if (JBD2_HAS_INCOMPAT_FEATURE(journal,
-                                       JBD2_FEATURE_INCOMPAT_CSUM_V2))
+                       if (jbd2_journal_has_csum_v2or3(journal))
                                descr_csum_size =
                                        sizeof(struct jbd2_journal_block_tail);
                        if (descr_csum_size > 0 &&
@@ -574,7 +579,7 @@ static int do_one_pass(journal_t *journal,
                                        unsigned long long blocknr;
 
                                        J_ASSERT(obh != NULL);
-                                       blocknr = read_tag_block(tag_bytes,
+                                       blocknr = read_tag_block(journal,
                                                                 tag);
 
                                        /* If the block has been
@@ -598,7 +603,8 @@ static int do_one_pass(journal_t *journal,
                                                       "checksum recovering "
                                                       "block %llu in log\n",
                                                       blocknr);
-                                               continue;
+                                               block_error = 1;
+                                               goto skip_write;
                                        }
 
                                        /* Find a buffer for the new
@@ -797,7 +803,8 @@ static int do_one_pass(journal_t *journal,
                                success = -EIO;
                }
        }
-
+       if (block_error && success == 0)
+               success = -EIO;
        return success;
 
  failed:
@@ -811,7 +818,7 @@ static int jbd2_revoke_block_csum_verify(journal_t *j,
        __be32 provided;
        __u32 calculated;
 
-       if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2))
+       if (!jbd2_journal_has_csum_v2or3(j))
                return 1;
 
        tail = (struct jbd2_journal_revoke_tail *)(buf + j->j_blocksize -
index 198c9c10276dadf45983f3615f0804f27ee085e7..d5e95a175c9244a24f26b52b4b9755ceee6f1400 100644 (file)
@@ -91,8 +91,8 @@
 #include <linux/list.h>
 #include <linux/init.h>
 #include <linux/bio.h>
-#endif
 #include <linux/log2.h>
+#endif
 
 static struct kmem_cache *jbd2_revoke_record_cache;
 static struct kmem_cache *jbd2_revoke_table_cache;
@@ -597,7 +597,7 @@ static void write_one_revoke_record(journal_t *journal,
        offset = *offsetp;
 
        /* Do we need to leave space at the end for a checksum? */
-       if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2))
+       if (jbd2_journal_has_csum_v2or3(journal))
                csum_size = sizeof(struct jbd2_journal_revoke_tail);
 
        /* Make sure we have a descriptor with space left for the record */
@@ -644,7 +644,7 @@ static void jbd2_revoke_csum_set(journal_t *j, struct buffer_head *bh)
        struct jbd2_journal_revoke_tail *tail;
        __u32 csum;
 
-       if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2))
+       if (!jbd2_journal_has_csum_v2or3(j))
                return;
 
        tail = (struct jbd2_journal_revoke_tail *)(bh->b_data + j->j_blocksize -
index a6f54802d277304b2f483eb61af3ae6b574a79f9..bb08857f90b56cb2b51a77b3f69acfef33a8fd9c 100644 (file)
@@ -247,6 +247,18 @@ void locks_free_lock(struct file_lock *fl)
 }
 EXPORT_SYMBOL(locks_free_lock);
 
+static void
+locks_dispose_list(struct list_head *dispose)
+{
+       struct file_lock *fl;
+
+       while (!list_empty(dispose)) {
+               fl = list_first_entry(dispose, struct file_lock, fl_block);
+               list_del_init(&fl->fl_block);
+               locks_free_lock(fl);
+       }
+}
+
 void locks_init_lock(struct file_lock *fl)
 {
        memset(fl, 0, sizeof(struct file_lock));
@@ -285,7 +297,8 @@ EXPORT_SYMBOL(__locks_copy_lock);
 
 void locks_copy_lock(struct file_lock *new, struct file_lock *fl)
 {
-       locks_release_private(new);
+       /* "new" must be a freshly-initialized lock */
+       WARN_ON_ONCE(new->fl_ops);
 
        __locks_copy_lock(new, fl);
        new->fl_file = fl->fl_file;
@@ -650,12 +663,16 @@ static void locks_unlink_lock(struct file_lock **thisfl_p)
  *
  * Must be called with i_lock held!
  */
-static void locks_delete_lock(struct file_lock **thisfl_p)
+static void locks_delete_lock(struct file_lock **thisfl_p,
+                             struct list_head *dispose)
 {
        struct file_lock *fl = *thisfl_p;
 
        locks_unlink_lock(thisfl_p);
-       locks_free_lock(fl);
+       if (dispose)
+               list_add(&fl->fl_block, dispose);
+       else
+               locks_free_lock(fl);
 }
 
 /* Determine if lock sys_fl blocks lock caller_fl. Common functionality
@@ -811,6 +828,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
        struct inode * inode = file_inode(filp);
        int error = 0;
        int found = 0;
+       LIST_HEAD(dispose);
 
        if (!(request->fl_flags & FL_ACCESS) && (request->fl_type != F_UNLCK)) {
                new_fl = locks_alloc_lock();
@@ -833,7 +851,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
                if (request->fl_type == fl->fl_type)
                        goto out;
                found = 1;
-               locks_delete_lock(before);
+               locks_delete_lock(before, &dispose);
                break;
        }
 
@@ -880,6 +898,7 @@ out:
        spin_unlock(&inode->i_lock);
        if (new_fl)
                locks_free_lock(new_fl);
+       locks_dispose_list(&dispose);
        return error;
 }
 
@@ -893,6 +912,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
        struct file_lock **before;
        int error;
        bool added = false;
+       LIST_HEAD(dispose);
 
        /*
         * We may need two file_lock structures for this operation,
@@ -988,7 +1008,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
                        else
                                request->fl_end = fl->fl_end;
                        if (added) {
-                               locks_delete_lock(before);
+                               locks_delete_lock(before, &dispose);
                                continue;
                        }
                        request = fl;
@@ -1018,21 +1038,24 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
                                 * one (This may happen several times).
                                 */
                                if (added) {
-                                       locks_delete_lock(before);
+                                       locks_delete_lock(before, &dispose);
                                        continue;
                                }
-                               /* Replace the old lock with the new one.
-                                * Wake up anybody waiting for the old one,
-                                * as the change in lock type might satisfy
-                                * their needs.
+                               /*
+                                * Replace the old lock with new_fl, and
+                                * remove the old one. It's safe to do the
+                                * insert here since we know that we won't be
+                                * using new_fl later, and that the lock is
+                                * just replacing an existing lock.
                                 */
-                               locks_wake_up_blocks(fl);
-                               fl->fl_start = request->fl_start;
-                               fl->fl_end = request->fl_end;
-                               fl->fl_type = request->fl_type;
-                               locks_release_private(fl);
-                               locks_copy_private(fl, request);
-                               request = fl;
+                               error = -ENOLCK;
+                               if (!new_fl)
+                                       goto out;
+                               locks_copy_lock(new_fl, request);
+                               request = new_fl;
+                               new_fl = NULL;
+                               locks_delete_lock(before, &dispose);
+                               locks_insert_lock(before, request);
                                added = true;
                        }
                }
@@ -1093,6 +1116,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
                locks_free_lock(new_fl);
        if (new_fl2)
                locks_free_lock(new_fl2);
+       locks_dispose_list(&dispose);
        return error;
 }
 
@@ -1268,7 +1292,7 @@ int lease_modify(struct file_lock **before, int arg)
                        printk(KERN_ERR "locks_delete_lock: fasync == %p\n", fl->fl_fasync);
                        fl->fl_fasync = NULL;
                }
-               locks_delete_lock(before);
+               locks_delete_lock(before, NULL);
        }
        return 0;
 }
@@ -1595,7 +1619,7 @@ static int generic_add_lease(struct file *filp, long arg, struct file_lock **flp
        smp_mb();
        error = check_conflicting_open(dentry, arg);
        if (error)
-               locks_unlink_lock(flp);
+               locks_unlink_lock(before);
 out:
        if (is_deleg)
                mutex_unlock(&inode->i_mutex);
@@ -1737,13 +1761,10 @@ static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg)
        ret = fl;
        spin_lock(&inode->i_lock);
        error = __vfs_setlease(filp, arg, &ret);
-       if (error) {
-               spin_unlock(&inode->i_lock);
-               locks_free_lock(fl);
-               goto out_free_fasync;
-       }
-       if (ret != fl)
-               locks_free_lock(fl);
+       if (error)
+               goto out_unlock;
+       if (ret == fl)
+               fl = NULL;
 
        /*
         * fasync_insert_entry() returns the old entry if any.
@@ -1755,9 +1776,10 @@ static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg)
                new = NULL;
 
        error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0);
+out_unlock:
        spin_unlock(&inode->i_lock);
-
-out_free_fasync:
+       if (fl)
+               locks_free_lock(fl);
        if (new)
                fasync_free(new);
        return error;
@@ -2320,6 +2342,7 @@ void locks_remove_file(struct file *filp)
        struct inode * inode = file_inode(filp);
        struct file_lock *fl;
        struct file_lock **before;
+       LIST_HEAD(dispose);
 
        if (!inode->i_flock)
                return;
@@ -2365,12 +2388,13 @@ void locks_remove_file(struct file *filp)
                                fl->fl_type, fl->fl_flags,
                                fl->fl_start, fl->fl_end);
 
-                       locks_delete_lock(before);
+                       locks_delete_lock(before, &dispose);
                        continue;
                }
                before = &fl->fl_next;
        }
        spin_unlock(&inode->i_lock);
+       locks_dispose_list(&dispose);
 }
 
 /**
@@ -2452,7 +2476,11 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl,
                        seq_puts(f, "FLOCK  ADVISORY  ");
                }
        } else if (IS_LEASE(fl)) {
-               seq_puts(f, "LEASE  ");
+               if (fl->fl_flags & FL_DELEG)
+                       seq_puts(f, "DELEG  ");
+               else
+                       seq_puts(f, "LEASE  ");
+
                if (lease_breaking(fl))
                        seq_puts(f, "BREAKING  ");
                else if (fl->fl_file)
index a01c7730e9af3ad07f3e993d2f7f27f04f615604..ef42d9bee2121f8e6a68937a5ecaa7670721ded9 100644 (file)
@@ -1217,6 +1217,11 @@ static void namespace_unlock(void)
        head.first->pprev = &head.first;
        INIT_HLIST_HEAD(&unmounted);
 
+       /* undo decrements we'd done in umount_tree() */
+       hlist_for_each_entry(mnt, &head, mnt_hash)
+               if (mnt->mnt_ex_mountpoint.mnt)
+                       mntget(mnt->mnt_ex_mountpoint.mnt);
+
        up_write(&namespace_sem);
 
        synchronize_rcu();
@@ -1253,6 +1258,9 @@ void umount_tree(struct mount *mnt, int how)
                hlist_add_head(&p->mnt_hash, &tmp_list);
        }
 
+       hlist_for_each_entry(p, &tmp_list, mnt_hash)
+               list_del_init(&p->mnt_child);
+
        if (how)
                propagate_umount(&tmp_list);
 
@@ -1263,9 +1271,9 @@ void umount_tree(struct mount *mnt, int how)
                p->mnt_ns = NULL;
                if (how < 2)
                        p->mnt.mnt_flags |= MNT_SYNC_UMOUNT;
-               list_del_init(&p->mnt_child);
                if (mnt_has_parent(p)) {
                        put_mountpoint(p->mnt_mp);
+                       mnt_add_count(p->mnt_parent, -1);
                        /* move the reference to mountpoint into ->mnt_ex_mountpoint */
                        p->mnt_ex_mountpoint.dentry = p->mnt_mountpoint;
                        p->mnt_ex_mountpoint.mnt = &p->mnt_parent->mnt;
index d0fec260132add4ce0d8917cd1bb47c15408be90..24c6898159cc1ea5e2622574968ff1bbf62268b5 100644 (file)
@@ -129,7 +129,10 @@ static int __nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
                .rpc_argp       = &args,
                .rpc_resp       = &fattr,
        };
-       int status;
+       int status = 0;
+
+       if (acl == NULL && (!S_ISDIR(inode->i_mode) || dfacl == NULL))
+               goto out;
 
        status = -EOPNOTSUPP;
        if (!nfs_server_capable(inode, NFS_CAP_ACLS))
index 75ae8d22f067d55b7edfe77bbb44d2b0067880f8..7dd8aca31c29b9c0079dce94136e70d716072f78 100644 (file)
@@ -2560,6 +2560,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
        struct nfs4_closedata *calldata = data;
        struct nfs4_state *state = calldata->state;
        struct nfs_server *server = NFS_SERVER(calldata->inode);
+       nfs4_stateid *res_stateid = NULL;
 
        dprintk("%s: begin!\n", __func__);
        if (!nfs4_sequence_done(task, &calldata->res.seq_res))
@@ -2570,12 +2571,12 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
         */
        switch (task->tk_status) {
                case 0:
-                       if (calldata->roc)
+                       res_stateid = &calldata->res.stateid;
+                       if (calldata->arg.fmode == 0 && calldata->roc)
                                pnfs_roc_set_barrier(state->inode,
                                                     calldata->roc_barrier);
-                       nfs_clear_open_stateid(state, &calldata->res.stateid, 0);
                        renew_lease(server, calldata->timestamp);
-                       goto out_release;
+                       break;
                case -NFS4ERR_ADMIN_REVOKED:
                case -NFS4ERR_STALE_STATEID:
                case -NFS4ERR_OLD_STATEID:
@@ -2589,7 +2590,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
                                goto out_release;
                        }
        }
-       nfs_clear_open_stateid(state, NULL, calldata->arg.fmode);
+       nfs_clear_open_stateid(state, res_stateid, calldata->arg.fmode);
 out_release:
        nfs_release_seqid(calldata->arg.seqid);
        nfs_refresh_inode(calldata->inode, calldata->res.fattr);
@@ -2601,6 +2602,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
        struct nfs4_closedata *calldata = data;
        struct nfs4_state *state = calldata->state;
        struct inode *inode = calldata->inode;
+       bool is_rdonly, is_wronly, is_rdwr;
        int call_close = 0;
 
        dprintk("%s: begin!\n", __func__);
@@ -2608,18 +2610,24 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
                goto out_wait;
 
        task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE];
-       calldata->arg.fmode = FMODE_READ|FMODE_WRITE;
        spin_lock(&state->owner->so_lock);
+       is_rdwr = test_bit(NFS_O_RDWR_STATE, &state->flags);
+       is_rdonly = test_bit(NFS_O_RDONLY_STATE, &state->flags);
+       is_wronly = test_bit(NFS_O_WRONLY_STATE, &state->flags);
+       /* Calculate the current open share mode */
+       calldata->arg.fmode = 0;
+       if (is_rdonly || is_rdwr)
+               calldata->arg.fmode |= FMODE_READ;
+       if (is_wronly || is_rdwr)
+               calldata->arg.fmode |= FMODE_WRITE;
        /* Calculate the change in open mode */
        if (state->n_rdwr == 0) {
                if (state->n_rdonly == 0) {
-                       call_close |= test_bit(NFS_O_RDONLY_STATE, &state->flags);
-                       call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags);
+                       call_close |= is_rdonly || is_rdwr;
                        calldata->arg.fmode &= ~FMODE_READ;
                }
                if (state->n_wronly == 0) {
-                       call_close |= test_bit(NFS_O_WRONLY_STATE, &state->flags);
-                       call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags);
+                       call_close |= is_wronly || is_rdwr;
                        calldata->arg.fmode &= ~FMODE_WRITE;
                }
        }
index ba491926df5f7df2db1e224c96e7e070bd36dcec..be7cbce6e4c7a71c0fbd22a03193e20c9fec55ce 100644 (file)
@@ -116,7 +116,7 @@ __nfs_iocounter_wait(struct nfs_io_counter *c)
                if (atomic_read(&c->io_count) == 0)
                        break;
                ret = nfs_wait_bit_killable(&q.key);
-       } while (atomic_read(&c->io_count) != 0);
+       } while (atomic_read(&c->io_count) != 0 && !ret);
        finish_wait(wq, &q.wait);
        return ret;
 }
@@ -139,26 +139,49 @@ nfs_iocounter_wait(struct nfs_io_counter *c)
 /*
  * nfs_page_group_lock - lock the head of the page group
  * @req - request in group that is to be locked
+ * @nonblock - if true don't block waiting for lock
  *
  * this lock must be held if modifying the page group list
  *
- * returns result from wait_on_bit_lock: 0 on success, < 0 on error
+ * return 0 on success, < 0 on error: -EDELAY if nonblocking or the
+ * result from wait_on_bit_lock
+ *
+ * NOTE: calling with nonblock=false should always have set the
+ *       lock bit (see fs/buffer.c and other uses of wait_on_bit_lock
+ *       with TASK_UNINTERRUPTIBLE), so there is no need to check the result.
  */
 int
-nfs_page_group_lock(struct nfs_page *req, bool wait)
+nfs_page_group_lock(struct nfs_page *req, bool nonblock)
 {
        struct nfs_page *head = req->wb_head;
-       int ret;
 
        WARN_ON_ONCE(head != head->wb_head);
 
-       do {
-               ret = wait_on_bit_lock(&head->wb_flags, PG_HEADLOCK,
-                       TASK_UNINTERRUPTIBLE);
-       } while (wait && ret != 0);
+       if (!test_and_set_bit(PG_HEADLOCK, &head->wb_flags))
+               return 0;
 
-       WARN_ON_ONCE(ret > 0);
-       return ret;
+       if (!nonblock)
+               return wait_on_bit_lock(&head->wb_flags, PG_HEADLOCK,
+                               TASK_UNINTERRUPTIBLE);
+
+       return -EAGAIN;
+}
+
+/*
+ * nfs_page_group_lock_wait - wait for the lock to clear, but don't grab it
+ * @req - a request in the group
+ *
+ * This is a blocking call to wait for the group lock to be cleared.
+ */
+void
+nfs_page_group_lock_wait(struct nfs_page *req)
+{
+       struct nfs_page *head = req->wb_head;
+
+       WARN_ON_ONCE(head != head->wb_head);
+
+       wait_on_bit(&head->wb_flags, PG_HEADLOCK,
+               TASK_UNINTERRUPTIBLE);
 }
 
 /*
@@ -219,7 +242,7 @@ bool nfs_page_group_sync_on_bit(struct nfs_page *req, unsigned int bit)
 {
        bool ret;
 
-       nfs_page_group_lock(req, true);
+       nfs_page_group_lock(req, false);
        ret = nfs_page_group_sync_on_bit_locked(req, bit);
        nfs_page_group_unlock(req);
 
@@ -701,10 +724,11 @@ int nfs_generic_pgio(struct nfs_pageio_descriptor *desc,
                     struct nfs_pgio_header *hdr)
 {
        struct nfs_page         *req;
-       struct page             **pages;
+       struct page             **pages,
+                               *last_page;
        struct list_head *head = &desc->pg_list;
        struct nfs_commit_info cinfo;
-       unsigned int pagecount;
+       unsigned int pagecount, pageused;
 
        pagecount = nfs_page_array_len(desc->pg_base, desc->pg_count);
        if (!nfs_pgarray_set(&hdr->page_array, pagecount))
@@ -712,12 +736,23 @@ int nfs_generic_pgio(struct nfs_pageio_descriptor *desc,
 
        nfs_init_cinfo(&cinfo, desc->pg_inode, desc->pg_dreq);
        pages = hdr->page_array.pagevec;
+       last_page = NULL;
+       pageused = 0;
        while (!list_empty(head)) {
                req = nfs_list_entry(head->next);
                nfs_list_remove_request(req);
                nfs_list_add_request(req, &hdr->pages);
-               *pages++ = req->wb_page;
+
+               if (WARN_ON_ONCE(pageused >= pagecount))
+                       return nfs_pgio_error(desc, hdr);
+
+               if (!last_page || last_page != req->wb_page) {
+                       *pages++ = last_page = req->wb_page;
+                       pageused++;
+               }
        }
+       if (WARN_ON_ONCE(pageused != pagecount))
+               return nfs_pgio_error(desc, hdr);
 
        if ((desc->pg_ioflags & FLUSH_COND_STABLE) &&
            (desc->pg_moreio || nfs_reqs_to_commit(&cinfo)))
@@ -788,6 +823,14 @@ static bool nfs_can_coalesce_requests(struct nfs_page *prev,
                        return false;
                if (req_offset(req) != req_offset(prev) + prev->wb_bytes)
                        return false;
+               if (req->wb_page == prev->wb_page) {
+                       if (req->wb_pgbase != prev->wb_pgbase + prev->wb_bytes)
+                               return false;
+               } else {
+                       if (req->wb_pgbase != 0 ||
+                           prev->wb_pgbase + prev->wb_bytes != PAGE_CACHE_SIZE)
+                               return false;
+               }
        }
        size = pgio->pg_ops->pg_test(pgio, prev, req);
        WARN_ON_ONCE(size > req->wb_bytes);
@@ -858,13 +901,8 @@ static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
        struct nfs_page *subreq;
        unsigned int bytes_left = 0;
        unsigned int offset, pgbase;
-       int ret;
 
-       ret = nfs_page_group_lock(req, false);
-       if (ret < 0) {
-               desc->pg_error = ret;
-               return 0;
-       }
+       nfs_page_group_lock(req, false);
 
        subreq = req;
        bytes_left = subreq->wb_bytes;
@@ -886,11 +924,7 @@ static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
                        if (desc->pg_recoalesce)
                                return 0;
                        /* retry add_request for this subreq */
-                       ret = nfs_page_group_lock(req, false);
-                       if (ret < 0) {
-                               desc->pg_error = ret;
-                               return 0;
-                       }
+                       nfs_page_group_lock(req, false);
                        continue;
                }
 
index e3b5cf28bdc5c2dbfba5d3c16b06b5724afe6c60..175d5d073ccf350db485daf81ab3030555d80a60 100644 (file)
@@ -241,7 +241,7 @@ static bool nfs_page_group_covers_page(struct nfs_page *req)
        unsigned int pos = 0;
        unsigned int len = nfs_page_length(req->wb_page);
 
-       nfs_page_group_lock(req, true);
+       nfs_page_group_lock(req, false);
 
        do {
                tmp = nfs_page_group_search_locked(req->wb_head, pos);
@@ -478,10 +478,23 @@ try_again:
                return NULL;
        }
 
-       /* lock each request in the page group */
-       ret = nfs_page_group_lock(head, false);
-       if (ret < 0)
+       /* holding inode lock, so always make a non-blocking call to try the
+        * page group lock */
+       ret = nfs_page_group_lock(head, true);
+       if (ret < 0) {
+               spin_unlock(&inode->i_lock);
+
+               if (!nonblock && ret == -EAGAIN) {
+                       nfs_page_group_lock_wait(head);
+                       nfs_release_request(head);
+                       goto try_again;
+               }
+
+               nfs_release_request(head);
                return ERR_PTR(ret);
+       }
+
+       /* lock each request in the page group */
        subreq = head;
        do {
                /*
index 1ec141e758d73497288f35a13f4e7a965f381a30..62e8ec619b4ce54f6509fcfa2f33cfc381f4fd5e 100644 (file)
@@ -160,9 +160,18 @@ static void o2quo_make_decision(struct work_struct *work)
        }
 
 out:
-       spin_unlock(&qs->qs_lock);
-       if (fence)
+       if (fence) {
+               spin_unlock(&qs->qs_lock);
                o2quo_fence_self();
+       } else {
+               mlog(ML_NOTICE, "not fencing this node, heartbeating: %d, "
+                       "connected: %d, lowest: %d (%sreachable)\n",
+                       qs->qs_heartbeating, qs->qs_connected, lowest_hb,
+                       lowest_reachable ? "" : "un");
+               spin_unlock(&qs->qs_lock);
+
+       }
+
 }
 
 static void o2quo_set_hold(struct o2quo_state *qs, u8 node)
index 681691bc233a1d8991ba4ec5ad1512524afd1b8d..ea34952f9496a6bfaa698165d6b818bd601ebf17 100644 (file)
@@ -1480,6 +1480,14 @@ static int o2net_set_nodelay(struct socket *sock)
        return ret;
 }
 
+static int o2net_set_usertimeout(struct socket *sock)
+{
+       int user_timeout = O2NET_TCP_USER_TIMEOUT;
+
+       return kernel_setsockopt(sock, SOL_TCP, TCP_USER_TIMEOUT,
+                               (char *)&user_timeout, sizeof(user_timeout));
+}
+
 static void o2net_initialize_handshake(void)
 {
        o2net_hand->o2hb_heartbeat_timeout_ms = cpu_to_be32(
@@ -1536,16 +1544,20 @@ static void o2net_idle_timer(unsigned long data)
 #endif
 
        printk(KERN_NOTICE "o2net: Connection to " SC_NODEF_FMT " has been "
-              "idle for %lu.%lu secs, shutting it down.\n", SC_NODEF_ARGS(sc),
-              msecs / 1000, msecs % 1000);
+              "idle for %lu.%lu secs.\n",
+              SC_NODEF_ARGS(sc), msecs / 1000, msecs % 1000);
 
-       /*
-        * Initialize the nn_timeout so that the next connection attempt
-        * will continue in o2net_start_connect.
+       /* idle timerout happen, don't shutdown the connection, but
+        * make fence decision. Maybe the connection can recover before
+        * the decision is made.
         */
        atomic_set(&nn->nn_timeout, 1);
+       o2quo_conn_err(o2net_num_from_nn(nn));
+       queue_delayed_work(o2net_wq, &nn->nn_still_up,
+                       msecs_to_jiffies(O2NET_QUORUM_DELAY_MS));
+
+       o2net_sc_reset_idle_timer(sc);
 
-       o2net_sc_queue_work(sc, &sc->sc_shutdown_work);
 }
 
 static void o2net_sc_reset_idle_timer(struct o2net_sock_container *sc)
@@ -1560,6 +1572,15 @@ static void o2net_sc_reset_idle_timer(struct o2net_sock_container *sc)
 
 static void o2net_sc_postpone_idle(struct o2net_sock_container *sc)
 {
+       struct o2net_node *nn = o2net_nn_from_num(sc->sc_node->nd_num);
+
+       /* clear fence decision since the connection recover from timeout*/
+       if (atomic_read(&nn->nn_timeout)) {
+               o2quo_conn_up(o2net_num_from_nn(nn));
+               cancel_delayed_work(&nn->nn_still_up);
+               atomic_set(&nn->nn_timeout, 0);
+       }
+
        /* Only push out an existing timer */
        if (timer_pending(&sc->sc_idle_timeout))
                o2net_sc_reset_idle_timer(sc);
@@ -1650,6 +1671,12 @@ static void o2net_start_connect(struct work_struct *work)
                goto out;
        }
 
+       ret = o2net_set_usertimeout(sock);
+       if (ret) {
+               mlog(ML_ERROR, "set TCP_USER_TIMEOUT failed with %d\n", ret);
+               goto out;
+       }
+
        o2net_register_callbacks(sc->sc_sock->sk, sc);
 
        spin_lock(&nn->nn_lock);
@@ -1831,6 +1858,12 @@ static int o2net_accept_one(struct socket *sock, int *more)
                goto out;
        }
 
+       ret = o2net_set_usertimeout(new_sock);
+       if (ret) {
+               mlog(ML_ERROR, "set TCP_USER_TIMEOUT failed with %d\n", ret);
+               goto out;
+       }
+
        slen = sizeof(sin);
        ret = new_sock->ops->getname(new_sock, (struct sockaddr *) &sin,
                                       &slen, 1);
index 5bada2a69b503cd365d626a25e4ae6d08ad50b7a..c571e849fda482b17bc89c93f3cebcf4d1229be3 100644 (file)
@@ -63,6 +63,7 @@ typedef void (o2net_post_msg_handler_func)(int status, void *data,
 #define O2NET_KEEPALIVE_DELAY_MS_DEFAULT       2000
 #define O2NET_IDLE_TIMEOUT_MS_DEFAULT          30000
 
+#define O2NET_TCP_USER_TIMEOUT                 0x7fffffff
 
 /* TODO: figure this out.... */
 static inline int o2net_link_down(int err, struct socket *sock)
index 6f66b3751ace1c032dcbbfbb49bf87444702479a..53e6c40ed4c6a451bc38d0727176c0827e564930 100644 (file)
@@ -35,9 +35,8 @@
                copy_to_user((typeof(a) __user *)b, &(a), sizeof(a))
 
 /*
- * This call is void because we are already reporting an error that may
- * be -EFAULT.  The error will be returned from the ioctl(2) call.  It's
- * just a best-effort to tell userspace that this request caused the error.
+ * This is just a best-effort to tell userspace that this request
+ * caused the error.
  */
 static inline void o2info_set_request_error(struct ocfs2_info_request *kreq,
                                        struct ocfs2_info_request __user *req)
@@ -146,136 +145,105 @@ bail:
 static int ocfs2_info_handle_blocksize(struct inode *inode,
                                       struct ocfs2_info_request __user *req)
 {
-       int status = -EFAULT;
        struct ocfs2_info_blocksize oib;
 
        if (o2info_from_user(oib, req))
-               goto bail;
+               return -EFAULT;
 
        oib.ib_blocksize = inode->i_sb->s_blocksize;
 
        o2info_set_request_filled(&oib.ib_req);
 
        if (o2info_to_user(oib, req))
-               goto bail;
-
-       status = 0;
-bail:
-       if (status)
-               o2info_set_request_error(&oib.ib_req, req);
+               return -EFAULT;
 
-       return status;
+       return 0;
 }
 
 static int ocfs2_info_handle_clustersize(struct inode *inode,
                                         struct ocfs2_info_request __user *req)
 {
-       int status = -EFAULT;
        struct ocfs2_info_clustersize oic;
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
 
        if (o2info_from_user(oic, req))
-               goto bail;
+               return -EFAULT;
 
        oic.ic_clustersize = osb->s_clustersize;
 
        o2info_set_request_filled(&oic.ic_req);
 
        if (o2info_to_user(oic, req))
-               goto bail;
-
-       status = 0;
-bail:
-       if (status)
-               o2info_set_request_error(&oic.ic_req, req);
+               return -EFAULT;
 
-       return status;
+       return 0;
 }
 
 static int ocfs2_info_handle_maxslots(struct inode *inode,
                                      struct ocfs2_info_request __user *req)
 {
-       int status = -EFAULT;
        struct ocfs2_info_maxslots oim;
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
 
        if (o2info_from_user(oim, req))
-               goto bail;
+               return -EFAULT;
 
        oim.im_max_slots = osb->max_slots;
 
        o2info_set_request_filled(&oim.im_req);
 
        if (o2info_to_user(oim, req))
-               goto bail;
+               return -EFAULT;
 
-       status = 0;
-bail:
-       if (status)
-               o2info_set_request_error(&oim.im_req, req);
-
-       return status;
+       return 0;
 }
 
 static int ocfs2_info_handle_label(struct inode *inode,
                                   struct ocfs2_info_request __user *req)
 {
-       int status = -EFAULT;
        struct ocfs2_info_label oil;
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
 
        if (o2info_from_user(oil, req))
-               goto bail;
+               return -EFAULT;
 
        memcpy(oil.il_label, osb->vol_label, OCFS2_MAX_VOL_LABEL_LEN);
 
        o2info_set_request_filled(&oil.il_req);
 
        if (o2info_to_user(oil, req))
-               goto bail;
+               return -EFAULT;
 
-       status = 0;
-bail:
-       if (status)
-               o2info_set_request_error(&oil.il_req, req);
-
-       return status;
+       return 0;
 }
 
 static int ocfs2_info_handle_uuid(struct inode *inode,
                                  struct ocfs2_info_request __user *req)
 {
-       int status = -EFAULT;
        struct ocfs2_info_uuid oiu;
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
 
        if (o2info_from_user(oiu, req))
-               goto bail;
+               return -EFAULT;
 
        memcpy(oiu.iu_uuid_str, osb->uuid_str, OCFS2_TEXT_UUID_LEN + 1);
 
        o2info_set_request_filled(&oiu.iu_req);
 
        if (o2info_to_user(oiu, req))
-               goto bail;
-
-       status = 0;
-bail:
-       if (status)
-               o2info_set_request_error(&oiu.iu_req, req);
+               return -EFAULT;
 
-       return status;
+       return 0;
 }
 
 static int ocfs2_info_handle_fs_features(struct inode *inode,
                                         struct ocfs2_info_request __user *req)
 {
-       int status = -EFAULT;
        struct ocfs2_info_fs_features oif;
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
 
        if (o2info_from_user(oif, req))
-               goto bail;
+               return -EFAULT;
 
        oif.if_compat_features = osb->s_feature_compat;
        oif.if_incompat_features = osb->s_feature_incompat;
@@ -284,39 +252,28 @@ static int ocfs2_info_handle_fs_features(struct inode *inode,
        o2info_set_request_filled(&oif.if_req);
 
        if (o2info_to_user(oif, req))
-               goto bail;
+               return -EFAULT;
 
-       status = 0;
-bail:
-       if (status)
-               o2info_set_request_error(&oif.if_req, req);
-
-       return status;
+       return 0;
 }
 
 static int ocfs2_info_handle_journal_size(struct inode *inode,
                                          struct ocfs2_info_request __user *req)
 {
-       int status = -EFAULT;
        struct ocfs2_info_journal_size oij;
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
 
        if (o2info_from_user(oij, req))
-               goto bail;
+               return -EFAULT;
 
        oij.ij_journal_size = i_size_read(osb->journal->j_inode);
 
        o2info_set_request_filled(&oij.ij_req);
 
        if (o2info_to_user(oij, req))
-               goto bail;
+               return -EFAULT;
 
-       status = 0;
-bail:
-       if (status)
-               o2info_set_request_error(&oij.ij_req, req);
-
-       return status;
+       return 0;
 }
 
 static int ocfs2_info_scan_inode_alloc(struct ocfs2_super *osb,
@@ -373,7 +330,7 @@ static int ocfs2_info_handle_freeinode(struct inode *inode,
        u32 i;
        u64 blkno = -1;
        char namebuf[40];
-       int status = -EFAULT, type = INODE_ALLOC_SYSTEM_INODE;
+       int status, type = INODE_ALLOC_SYSTEM_INODE;
        struct ocfs2_info_freeinode *oifi = NULL;
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
        struct inode *inode_alloc = NULL;
@@ -385,8 +342,10 @@ static int ocfs2_info_handle_freeinode(struct inode *inode,
                goto out_err;
        }
 
-       if (o2info_from_user(*oifi, req))
-               goto bail;
+       if (o2info_from_user(*oifi, req)) {
+               status = -EFAULT;
+               goto out_free;
+       }
 
        oifi->ifi_slotnum = osb->max_slots;
 
@@ -424,14 +383,16 @@ static int ocfs2_info_handle_freeinode(struct inode *inode,
 
        o2info_set_request_filled(&oifi->ifi_req);
 
-       if (o2info_to_user(*oifi, req))
-               goto bail;
+       if (o2info_to_user(*oifi, req)) {
+               status = -EFAULT;
+               goto out_free;
+       }
 
        status = 0;
 bail:
        if (status)
                o2info_set_request_error(&oifi->ifi_req, req);
-
+out_free:
        kfree(oifi);
 out_err:
        return status;
@@ -658,7 +619,7 @@ static int ocfs2_info_handle_freefrag(struct inode *inode,
 {
        u64 blkno = -1;
        char namebuf[40];
-       int status = -EFAULT, type = GLOBAL_BITMAP_SYSTEM_INODE;
+       int status, type = GLOBAL_BITMAP_SYSTEM_INODE;
 
        struct ocfs2_info_freefrag *oiff;
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
@@ -671,8 +632,10 @@ static int ocfs2_info_handle_freefrag(struct inode *inode,
                goto out_err;
        }
 
-       if (o2info_from_user(*oiff, req))
-               goto bail;
+       if (o2info_from_user(*oiff, req)) {
+               status = -EFAULT;
+               goto out_free;
+       }
        /*
         * chunksize from userspace should be power of 2.
         */
@@ -711,14 +674,14 @@ static int ocfs2_info_handle_freefrag(struct inode *inode,
 
        if (o2info_to_user(*oiff, req)) {
                status = -EFAULT;
-               goto bail;
+               goto out_free;
        }
 
        status = 0;
 bail:
        if (status)
                o2info_set_request_error(&oiff->iff_req, req);
-
+out_free:
        kfree(oiff);
 out_err:
        return status;
@@ -727,23 +690,17 @@ out_err:
 static int ocfs2_info_handle_unknown(struct inode *inode,
                                     struct ocfs2_info_request __user *req)
 {
-       int status = -EFAULT;
        struct ocfs2_info_request oir;
 
        if (o2info_from_user(oir, req))
-               goto bail;
+               return -EFAULT;
 
        o2info_clear_request_filled(&oir);
 
        if (o2info_to_user(oir, req))
-               goto bail;
+               return -EFAULT;
 
-       status = 0;
-bail:
-       if (status)
-               o2info_set_request_error(&oir, req);
-
-       return status;
+       return 0;
 }
 
 /*
index 302bf22c4a30762013dbbfd64d0353250101eb62..aae331a5d03b2591e670c9a08451bd00ad8e66f9 100644 (file)
@@ -381,6 +381,7 @@ static void __propagate_umount(struct mount *mnt)
                 * other children
                 */
                if (child && list_empty(&child->mnt_mounts)) {
+                       list_del_init(&child->mnt_child);
                        hlist_del_init_rcu(&child->mnt_hash);
                        hlist_add_before_rcu(&child->mnt_hash, &mnt->mnt_hash);
                }
index b28d1dd10e8b70194a604a1fca654237edd817be..bdc729d80e5e4eb863ad4fcf849aa6ea886a7519 100644 (file)
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -65,7 +65,7 @@ int sync_filesystem(struct super_block *sb)
                return ret;
        return __sync_filesystem(sb, 1);
 }
-EXPORT_SYMBOL_GPL(sync_filesystem);
+EXPORT_SYMBOL(sync_filesystem);
 
 static void sync_inodes_one_sb(struct super_block *sb, void *arg)
 {
index 9737cba1357d754f4b1ea8927af83326865b8e54..83a06001742bfaab6781bc26509517196fc3af16 100644 (file)
@@ -1014,7 +1014,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry,
 
        fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);
        if (!fi)
-               goto out_no_entry;
+               goto out_fail;
        cfi.icb.extLength = cpu_to_le32(sb->s_blocksize);
        cfi.icb.extLocation = cpu_to_lelb(iinfo->i_location);
        if (UDF_SB(inode->i_sb)->s_lvid_bh) {
@@ -1036,6 +1036,7 @@ out:
 
 out_no_entry:
        up_write(&iinfo->i_data_sem);
+out_fail:
        inode_dec_link_count(inode);
        iput(inode);
        goto out;
index 7c580c97990ee05dee7e5ad42a9c5754bfe4384d..be7d42c7d9382bf8072a7e6e9eff7e03b24bab25 100644 (file)
@@ -902,9 +902,6 @@ void ufs_evict_inode(struct inode * inode)
        invalidate_inode_buffers(inode);
        clear_inode(inode);
 
-       if (want_delete) {
-               lock_ufs(inode->i_sb);
-               ufs_free_inode (inode);
-               unlock_ufs(inode->i_sb);
-       }
+       if (want_delete)
+               ufs_free_inode(inode);
 }
index 90d74b8f8eba8dacd536c74ac161cceddc241196..2df62a73f20ce2071c17d81c343ada85ae287d2a 100644 (file)
@@ -126,12 +126,12 @@ static int ufs_symlink (struct inode * dir, struct dentry * dentry,
        if (l > sb->s_blocksize)
                goto out_notlocked;
 
-       lock_ufs(dir->i_sb);
        inode = ufs_new_inode(dir, S_IFLNK | S_IRWXUGO);
        err = PTR_ERR(inode);
        if (IS_ERR(inode))
-               goto out;
+               goto out_notlocked;
 
+       lock_ufs(dir->i_sb);
        if (l > UFS_SB(sb)->s_uspi->s_maxsymlinklen) {
                /* slow symlink */
                inode->i_op = &ufs_symlink_inode_operations;
@@ -181,13 +181,9 @@ static int ufs_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode)
        struct inode * inode;
        int err;
 
-       lock_ufs(dir->i_sb);
-       inode_inc_link_count(dir);
-
        inode = ufs_new_inode(dir, S_IFDIR|mode);
-       err = PTR_ERR(inode);
        if (IS_ERR(inode))
-               goto out_dir;
+               return PTR_ERR(inode);
 
        inode->i_op = &ufs_dir_inode_operations;
        inode->i_fop = &ufs_dir_operations;
@@ -195,6 +191,9 @@ static int ufs_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode)
 
        inode_inc_link_count(inode);
 
+       lock_ufs(dir->i_sb);
+       inode_inc_link_count(dir);
+
        err = ufs_make_empty(inode, dir);
        if (err)
                goto out_fail;
@@ -212,7 +211,6 @@ out_fail:
        inode_dec_link_count(inode);
        inode_dec_link_count(inode);
        iput (inode);
-out_dir:
        inode_dec_link_count(dir);
        unlock_ufs(dir->i_sb);
        goto out;
index de2d26d328446e65698dca0ff9f4fe2317c3f04e..86df952d3e24e7054477338f479d325fa212ce0c 100644 (file)
@@ -5424,7 +5424,7 @@ xfs_bmap_shift_extents(
        struct xfs_bmap_free    *flist,
        int                     num_exts)
 {
-       struct xfs_btree_cur            *cur;
+       struct xfs_btree_cur            *cur = NULL;
        struct xfs_bmbt_rec_host        *gotp;
        struct xfs_bmbt_irec            got;
        struct xfs_bmbt_irec            left;
@@ -5435,7 +5435,7 @@ xfs_bmap_shift_extents(
        int                             error = 0;
        int                             i;
        int                             whichfork = XFS_DATA_FORK;
-       int                             logflags;
+       int                             logflags = 0;
        xfs_filblks_t                   blockcount = 0;
        int                             total_extents;
 
@@ -5478,16 +5478,11 @@ xfs_bmap_shift_extents(
                }
        }
 
-       /* We are going to change core inode */
-       logflags = XFS_ILOG_CORE;
        if (ifp->if_flags & XFS_IFBROOT) {
                cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork);
                cur->bc_private.b.firstblock = *firstblock;
                cur->bc_private.b.flist = flist;
                cur->bc_private.b.flags = 0;
-       } else {
-               cur = NULL;
-               logflags |= XFS_ILOG_DEXT;
        }
 
        /*
@@ -5545,11 +5540,14 @@ xfs_bmap_shift_extents(
                        blockcount = left.br_blockcount +
                                got.br_blockcount;
                        xfs_iext_remove(ip, *current_ext, 1, 0);
+                       logflags |= XFS_ILOG_CORE;
                        if (cur) {
                                error = xfs_btree_delete(cur, &i);
                                if (error)
                                        goto del_cursor;
                                XFS_WANT_CORRUPTED_GOTO(i == 1, del_cursor);
+                       } else {
+                               logflags |= XFS_ILOG_DEXT;
                        }
                        XFS_IFORK_NEXT_SET(ip, whichfork,
                                XFS_IFORK_NEXTENTS(ip, whichfork) - 1);
@@ -5575,6 +5573,7 @@ xfs_bmap_shift_extents(
                        got.br_startoff = startoff;
                }
 
+               logflags |= XFS_ILOG_CORE;
                if (cur) {
                        error = xfs_bmbt_update(cur, got.br_startoff,
                                                got.br_startblock,
@@ -5582,6 +5581,8 @@ xfs_bmap_shift_extents(
                                                got.br_state);
                        if (error)
                                goto del_cursor;
+               } else {
+                       logflags |= XFS_ILOG_DEXT;
                }
 
                (*current_ext)++;
@@ -5597,6 +5598,7 @@ del_cursor:
                xfs_btree_del_cursor(cur,
                        error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR);
 
-       xfs_trans_log_inode(tp, ip, logflags);
+       if (logflags)
+               xfs_trans_log_inode(tp, ip, logflags);
        return error;
 }
index 11e9b4caa54f168f7e429f5d7e5a01302d026e1c..b984647c24db02e98b4e030fd03c7bac75740923 100644 (file)
@@ -1753,11 +1753,72 @@ xfs_vm_readpages(
        return mpage_readpages(mapping, pages, nr_pages, xfs_get_blocks);
 }
 
+/*
+ * This is basically a copy of __set_page_dirty_buffers() with one
+ * small tweak: buffers beyond EOF do not get marked dirty. If we mark them
+ * dirty, we'll never be able to clean them because we don't write buffers
+ * beyond EOF, and that means we can't invalidate pages that span EOF
+ * that have been marked dirty. Further, the dirty state can leak into
+ * the file interior if the file is extended, resulting in all sorts of
+ * bad things happening as the state does not match the underlying data.
+ *
+ * XXX: this really indicates that bufferheads in XFS need to die. Warts like
+ * this only exist because of bufferheads and how the generic code manages them.
+ */
+STATIC int
+xfs_vm_set_page_dirty(
+       struct page             *page)
+{
+       struct address_space    *mapping = page->mapping;
+       struct inode            *inode = mapping->host;
+       loff_t                  end_offset;
+       loff_t                  offset;
+       int                     newly_dirty;
+
+       if (unlikely(!mapping))
+               return !TestSetPageDirty(page);
+
+       end_offset = i_size_read(inode);
+       offset = page_offset(page);
+
+       spin_lock(&mapping->private_lock);
+       if (page_has_buffers(page)) {
+               struct buffer_head *head = page_buffers(page);
+               struct buffer_head *bh = head;
+
+               do {
+                       if (offset < end_offset)
+                               set_buffer_dirty(bh);
+                       bh = bh->b_this_page;
+                       offset += 1 << inode->i_blkbits;
+               } while (bh != head);
+       }
+       newly_dirty = !TestSetPageDirty(page);
+       spin_unlock(&mapping->private_lock);
+
+       if (newly_dirty) {
+               /* sigh - __set_page_dirty() is static, so copy it here, too */
+               unsigned long flags;
+
+               spin_lock_irqsave(&mapping->tree_lock, flags);
+               if (page->mapping) {    /* Race with truncate? */
+                       WARN_ON_ONCE(!PageUptodate(page));
+                       account_page_dirtied(page, mapping);
+                       radix_tree_tag_set(&mapping->page_tree,
+                                       page_index(page), PAGECACHE_TAG_DIRTY);
+               }
+               spin_unlock_irqrestore(&mapping->tree_lock, flags);
+               __mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
+       }
+       return newly_dirty;
+}
+
 const struct address_space_operations xfs_address_space_operations = {
        .readpage               = xfs_vm_readpage,
        .readpages              = xfs_vm_readpages,
        .writepage              = xfs_vm_writepage,
        .writepages             = xfs_vm_writepages,
+       .set_page_dirty         = xfs_vm_set_page_dirty,
        .releasepage            = xfs_vm_releasepage,
        .invalidatepage         = xfs_vm_invalidatepage,
        .write_begin            = xfs_vm_write_begin,
index 2f1e30d39a3540f9d545e8ab9c5afd52af0047a9..1707980f9a4b564842cd435d9efc70571a5a9b18 100644 (file)
@@ -1470,6 +1470,26 @@ xfs_collapse_file_space(
        start_fsb = XFS_B_TO_FSB(mp, offset + len);
        shift_fsb = XFS_B_TO_FSB(mp, len);
 
+       /*
+        * Writeback the entire file and force remove any post-eof blocks. The
+        * writeback prevents changes to the extent list via concurrent
+        * writeback and the eofblocks trim prevents the extent shift algorithm
+        * from running into a post-eof delalloc extent.
+        *
+        * XXX: This is a temporary fix until the extent shift loop below is
+        * converted to use offsets and lookups within the ILOCK rather than
+        * carrying around the index into the extent list for the next
+        * iteration.
+        */
+       error = filemap_write_and_wait(VFS_I(ip)->i_mapping);
+       if (error)
+               return error;
+       if (xfs_can_free_eofblocks(ip, true)) {
+               error = xfs_free_eofblocks(mp, ip, false);
+               if (error)
+                       return error;
+       }
+
        error = xfs_free_file_space(ip, offset, len);
        if (error)
                return error;
index 076b1708d1345474ec2fd4e3a4c2e3bc605cb75a..de5368c803f9db192416e21032ade4535a0efcdd 100644 (file)
@@ -291,12 +291,22 @@ xfs_file_read_iter(
                if (inode->i_mapping->nrpages) {
                        ret = filemap_write_and_wait_range(
                                                        VFS_I(ip)->i_mapping,
-                                                       pos, -1);
+                                                       pos, pos + size - 1);
                        if (ret) {
                                xfs_rw_iunlock(ip, XFS_IOLOCK_EXCL);
                                return ret;
                        }
-                       truncate_pagecache_range(VFS_I(ip), pos, -1);
+
+                       /*
+                        * Invalidate whole pages. This can return an error if
+                        * we fail to invalidate a page, but this should never
+                        * happen on XFS. Warn if it does fail.
+                        */
+                       ret = invalidate_inode_pages2_range(VFS_I(ip)->i_mapping,
+                                       pos >> PAGE_CACHE_SHIFT,
+                                       (pos + size - 1) >> PAGE_CACHE_SHIFT);
+                       WARN_ON_ONCE(ret);
+                       ret = 0;
                }
                xfs_rw_ilock_demote(ip, XFS_IOLOCK_EXCL);
        }
@@ -632,10 +642,19 @@ xfs_file_dio_aio_write(
 
        if (mapping->nrpages) {
                ret = filemap_write_and_wait_range(VFS_I(ip)->i_mapping,
-                                                   pos, -1);
+                                                   pos, pos + count - 1);
                if (ret)
                        goto out;
-               truncate_pagecache_range(VFS_I(ip), pos, -1);
+               /*
+                * Invalidate whole pages. This can return an error if
+                * we fail to invalidate a page, but this should never
+                * happen on XFS. Warn if it does fail.
+                */
+               ret = invalidate_inode_pages2_range(VFS_I(ip)->i_mapping,
+                                       pos >> PAGE_CACHE_SHIFT,
+                                       (pos + count - 1) >> PAGE_CACHE_SHIFT);
+               WARN_ON_ONCE(ret);
+               ret = 0;
        }
 
        /*
index bcfd808b1098e81e410310e33582d814274188b8..c1c9de19edbe8abc62f2508bf9a7723bd9027d08 100644 (file)
@@ -246,7 +246,6 @@ struct acpi_device_pnp {
        acpi_device_name device_name;   /* Driver-determined */
        acpi_device_class device_class; /*        "          */
        union acpi_object *str_obj;     /* unicode string for _STR method */
-       unsigned long sun;              /* _SUN */
 };
 
 #define acpi_device_bid(d)     ((d)->pnp.bus_id)
index 6dfd64b3a6042d34176e85f25e73ed477a7c600e..e973540cd15baac6ab16836cdea2ce1df5ab10c7 100644 (file)
@@ -17,6 +17,7 @@
        {0x1002, 0x1315, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
        {0x1002, 0x1316, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
        {0x1002, 0x1317, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+       {0x1002, 0x1318, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
        {0x1002, 0x131B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
        {0x1002, 0x131C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
        {0x1002, 0x131D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
        {0x1002, 0x6601, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6602, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6603, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x6604, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x6605, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6606, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6607, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x6608, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6610, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6611, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6613, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6631, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_OLAND|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6640, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6641, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x6646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x6647, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6649, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6650, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6651, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6829, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x682A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x682B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x682C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x682D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x682F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6830, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
index 917dcd7965e7fb9b148029b2675cf1ee25f93671..e64ae7bf80a11f1eb6cd360225cbbc94eecd361b 100644 (file)
 #define  BCMA_RESET_CTL_RESET          0x0001
 #define BCMA_RESET_ST                  0x0804
 
+#define BCMA_NS_ROM_IOST_BOOT_DEV_MASK 0x0003
+#define BCMA_NS_ROM_IOST_BOOT_DEV_NOR  0x0000
+#define BCMA_NS_ROM_IOST_BOOT_DEV_NAND 0x0001
+#define BCMA_NS_ROM_IOST_BOOT_DEV_ROM  0x0002
+
 /* BCMA PCI config space registers. */
 #define BCMA_PCI_PMCSR                 0x44
 #define  BCMA_PCI_PE                   0x100
index eb726b9c57627f2e978751a9fe61fa910a2740f7..a1e31f274fcd55f7cfff245c8516d8e263206fb0 100644 (file)
@@ -127,10 +127,9 @@ enum {
        BLK_MQ_RQ_QUEUE_ERROR   = 2,    /* end IO with error */
 
        BLK_MQ_F_SHOULD_MERGE   = 1 << 0,
-       BLK_MQ_F_SHOULD_SORT    = 1 << 1,
-       BLK_MQ_F_TAG_SHARED     = 1 << 2,
-       BLK_MQ_F_SG_MERGE       = 1 << 3,
-       BLK_MQ_F_SYSFS_UP       = 1 << 4,
+       BLK_MQ_F_TAG_SHARED     = 1 << 1,
+       BLK_MQ_F_SG_MERGE       = 1 << 2,
+       BLK_MQ_F_SYSFS_UP       = 1 << 3,
 
        BLK_MQ_S_STOPPED        = 0,
        BLK_MQ_S_TAG_ACTIVE     = 1,
index 6f76277baf391733a3f9303f4f740b7151c5e96b..5bd35cc0d4715b44f886fff63b7f04a8db5f4969 100644 (file)
 #define PHY_ID_BCM5461                 0x002060c0
 #define PHY_ID_BCM57780                        0x03625d90
 
+#define PHY_ID_BCM7250                 0xae025280
+#define PHY_ID_BCM7364                 0xae025260
 #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_4                  0x600d8400
 #define PHY_BCM_OUI_5                  0x03625e00
-
+#define PHY_BCM_OUI_6                  0xae025000
 
 #define PHY_BCM_FLAGS_MODE_COPPER      0x00000001
 #define PHY_BCM_FLAGS_MODE_1000BX      0x00000002
 
 #define MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL      0x0000
 
+/*
+ * Broadcom LED source encodings.  These are used in BCM5461, BCM5481,
+ * BCM5482, and possibly some others.
+ */
+#define BCM_LED_SRC_LINKSPD1   0x0
+#define BCM_LED_SRC_LINKSPD2   0x1
+#define BCM_LED_SRC_XMITLED    0x2
+#define BCM_LED_SRC_ACTIVITYLED        0x3
+#define BCM_LED_SRC_FDXLED     0x4
+#define BCM_LED_SRC_SLAVE      0x5
+#define BCM_LED_SRC_INTR       0x6
+#define BCM_LED_SRC_QUALITY    0x7
+#define BCM_LED_SRC_RCVLED     0x8
+#define BCM_LED_SRC_MULTICOLOR1        0xa
+#define BCM_LED_SRC_OPENSHORT  0xb
+#define BCM_LED_SRC_OFF                0xe     /* Tied high */
+#define BCM_LED_SRC_ON         0xf     /* Tied low */
+
+
+/*
+ * BCM5482: Shadow registers
+ * Shadow values go into bits [14:10] of register 0x1c to select a shadow
+ * register to access.
+ */
+/* 00101: Spare Control Register 3 */
+#define BCM54XX_SHD_SCR3               0x05
+#define  BCM54XX_SHD_SCR3_DEF_CLK125   0x0001
+#define  BCM54XX_SHD_SCR3_DLLAPD_DIS   0x0002
+#define  BCM54XX_SHD_SCR3_TRDDAPD      0x0004
+
+/* 01010: Auto Power-Down */
+#define BCM54XX_SHD_APD                        0x0a
+#define  BCM54XX_SHD_APD_EN            0x0020
+
+#define BCM5482_SHD_LEDS1      0x0d    /* 01101: LED Selector 1 */
+                                       /* LED3 / ~LINKSPD[2] selector */
+#define BCM5482_SHD_LEDS1_LED3(src)    ((src & 0xf) << 4)
+                                       /* LED1 / ~LINKSPD[1] selector */
+#define BCM5482_SHD_LEDS1_LED1(src)    ((src & 0xf) << 0)
+#define BCM54XX_SHD_RGMII_MODE 0x0b    /* 01011: RGMII Mode Selector */
+#define BCM5482_SHD_SSD                0x14    /* 10100: Secondary SerDes control */
+#define BCM5482_SHD_SSD_LEDM   0x0008  /* SSD LED Mode enable */
+#define BCM5482_SHD_SSD_EN     0x0001  /* SSD enable */
+#define BCM5482_SHD_MODE       0x1f    /* 11111: Mode Control Register */
+#define BCM5482_SHD_MODE_1000BX        0x0001  /* Enable 1000BASE-X registers */
+
+
+/*
+ * EXPANSION SHADOW ACCESS REGISTERS.  (PHY REG 0x15, 0x16, and 0x17)
+ */
+#define MII_BCM54XX_EXP_AADJ1CH0               0x001f
+#define  MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN 0x0200
+#define  MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF   0x0100
+#define MII_BCM54XX_EXP_AADJ1CH3               0x601f
+#define  MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ     0x0002
+#define MII_BCM54XX_EXP_EXP08                  0x0F08
+#define  MII_BCM54XX_EXP_EXP08_RJCT_2MHZ       0x0001
+#define  MII_BCM54XX_EXP_EXP08_EARLY_DAC_WAKE  0x0200
+#define MII_BCM54XX_EXP_EXP75                  0x0f75
+#define  MII_BCM54XX_EXP_EXP75_VDACCTRL                0x003c
+#define  MII_BCM54XX_EXP_EXP75_CM_OSC          0x0001
+#define MII_BCM54XX_EXP_EXP96                  0x0f96
+#define  MII_BCM54XX_EXP_EXP96_MYST            0x0010
+#define MII_BCM54XX_EXP_EXP97                  0x0f97
+#define  MII_BCM54XX_EXP_EXP97_MYST            0x0c0c
+
+/*
+ * BCM5482: Secondary SerDes registers
+ */
+#define BCM5482_SSD_1000BX_CTL         0x00    /* 1000BASE-X Control */
+#define BCM5482_SSD_1000BX_CTL_PWRDOWN 0x0800  /* Power-down SSD */
+#define BCM5482_SSD_SGMII_SLAVE                0x15    /* SGMII Slave Register */
+#define BCM5482_SSD_SGMII_SLAVE_EN     0x0002  /* Slave mode enable */
+#define BCM5482_SSD_SGMII_SLAVE_AD     0x0001  /* Slave auto-detection */
+
+
+/*****************************************************************************/
+/* Fast Ethernet Transceiver definitions. */
+/*****************************************************************************/
+
+#define MII_BRCM_FET_INTREG            0x1a    /* Interrupt register */
+#define MII_BRCM_FET_IR_MASK           0x0100  /* Mask all interrupts */
+#define MII_BRCM_FET_IR_LINK_EN                0x0200  /* Link status change enable */
+#define MII_BRCM_FET_IR_SPEED_EN       0x0400  /* Link speed change enable */
+#define MII_BRCM_FET_IR_DUPLEX_EN      0x0800  /* Duplex mode change enable */
+#define MII_BRCM_FET_IR_ENABLE         0x4000  /* Interrupt enable */
+
+#define MII_BRCM_FET_BRCMTEST          0x1f    /* Brcm test register */
+#define MII_BRCM_FET_BT_SRE            0x0080  /* Shadow register enable */
+
+
+/*** Shadow register definitions ***/
+
+#define MII_BRCM_FET_SHDW_MISCCTRL     0x10    /* Shadow misc ctrl */
+#define MII_BRCM_FET_SHDW_MC_FAME      0x4000  /* Force Auto MDIX enable */
+
+#define MII_BRCM_FET_SHDW_AUXMODE4     0x1a    /* Auxiliary mode 4 */
+#define MII_BRCM_FET_SHDW_AM4_LED_MASK 0x0003
+#define MII_BRCM_FET_SHDW_AM4_LED_MODE1 0x0001
+
+#define MII_BRCM_FET_SHDW_AUXSTAT2     0x1b    /* Auxiliary status 2 */
+#define MII_BRCM_FET_SHDW_AS2_APDE     0x0020  /* Auto power down enable */
+
+/*
+ * Indirect register access functions for the 1000BASE-T/100BASE-TX/10BASE-T
+ * 0x1c shadow registers.
+ */
+static inline int bcm54xx_shadow_read(struct phy_device *phydev, u16 shadow)
+{
+       phy_write(phydev, MII_BCM54XX_SHD, MII_BCM54XX_SHD_VAL(shadow));
+       return MII_BCM54XX_SHD_DATA(phy_read(phydev, MII_BCM54XX_SHD));
+}
+
+static inline int bcm54xx_shadow_write(struct phy_device *phydev, u16 shadow,
+                                      u16 val)
+{
+       return phy_write(phydev, MII_BCM54XX_SHD,
+                        MII_BCM54XX_SHD_WRITE |
+                        MII_BCM54XX_SHD_VAL(shadow) |
+                        MII_BCM54XX_SHD_DATA(val));
+}
+
+#define BRCM_CL45VEN_EEE_CONTROL       0x803d
+#define LPI_FEATURE_EN                 0x8000
+#define LPI_FEATURE_EN_DIG1000X                0x4000
+
 #endif /* _LINUX_BRCMPHY_H */
diff --git a/include/linux/cycx_x25.h b/include/linux/cycx_x25.h
deleted file mode 100644 (file)
index 362bf19..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-#ifndef        _CYCX_X25_H
-#define        _CYCX_X25_H
-/*
-* cycx_x25.h   Cyclom X.25 firmware API definitions.
-*
-* Author:      Arnaldo Carvalho de Melo <acme@conectiva.com.br>
-*
-* Copyright:   (c) 1998-2003 Arnaldo Carvalho de Melo
-*
-* Based on sdla_x25.h by Gene Kozin <74604.152@compuserve.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.
-* ============================================================================
-* 2000/04/02   acme            dprintk and cycx_debug
-* 1999/01/03   acme            judicious use of data types
-* 1999/01/02   acme            #define X25_ACK_N3      0x4411
-* 1998/12/28   acme            cleanup: lot'o'things removed
-*                                       commands listed,
-*                                       TX25Cmd & TX25Config structs
-*                                       typedef'ed
-*/
-#ifndef PACKED
-#define PACKED __attribute__((packed))
-#endif 
-
-/* X.25 shared memory layout. */
-#define        X25_MBOX_OFFS   0x300   /* general mailbox block */
-#define        X25_RXMBOX_OFFS 0x340   /* receive mailbox */
-
-/* Debug */
-#define dprintk(level, format, a...) if (cycx_debug >= level) printk(format, ##a)
-
-extern unsigned int cycx_debug;
-
-/* Data Structures */
-/* X.25 Command Block. */
-struct cycx_x25_cmd {
-       u16 command;
-       u16 link;       /* values: 0 or 1 */
-       u16 len;        /* values: 0 thru 0x205 (517) */
-       u32 buf;
-} PACKED;
-
-/* Defines for the 'command' field. */
-#define X25_CONNECT_REQUEST             0x4401
-#define X25_CONNECT_RESPONSE            0x4402
-#define X25_DISCONNECT_REQUEST          0x4403
-#define X25_DISCONNECT_RESPONSE         0x4404
-#define X25_DATA_REQUEST                0x4405
-#define X25_ACK_TO_VC                  0x4406
-#define X25_INTERRUPT_RESPONSE          0x4407
-#define X25_CONFIG                      0x4408
-#define X25_CONNECT_INDICATION          0x4409
-#define X25_CONNECT_CONFIRM             0x440A
-#define X25_DISCONNECT_INDICATION       0x440B
-#define X25_DISCONNECT_CONFIRM          0x440C
-#define X25_DATA_INDICATION             0x440E
-#define X25_INTERRUPT_INDICATION        0x440F
-#define X25_ACK_FROM_VC                        0x4410
-#define X25_ACK_N3                     0x4411
-#define X25_CONNECT_COLLISION           0x4413
-#define X25_N3WIN                       0x4414
-#define X25_LINE_ON                     0x4415
-#define X25_LINE_OFF                    0x4416
-#define X25_RESET_REQUEST               0x4417
-#define X25_LOG                         0x4500
-#define X25_STATISTIC                   0x4600
-#define X25_TRACE                       0x4700
-#define X25_N2TRACEXC                   0x4702
-#define X25_N3TRACEXC                   0x4703
-
-/**
- *     struct cycx_x25_config - cyclom2x x25 firmware configuration
- *     @link - link number
- *     @speed - line speed
- *     @clock - internal/external
- *     @n2 - # of level 2 retransm.(values: 1 thru FF)
- *     @n2win - level 2 window (values: 1 thru 7)
- *     @n3win - level 3 window (values: 1 thru 7)
- *     @nvc - # of logical channels (values: 1 thru 64)
- *     @pktlen - level 3 packet length - log base 2 of size
- *     @locaddr - my address
- *     @remaddr - remote address
- *     @t1 - time, in seconds
- *     @t2 - time, in seconds
- *     @t21 - time, in seconds
- *     @npvc - # of permanent virt. circuits (1 thru nvc)
- *     @t23 - time, in seconds
- *     @flags - see dosx25.doc, in portuguese, for details
- */
-struct cycx_x25_config {
-       u8  link;
-       u8  speed;
-       u8  clock;
-       u8  n2;
-       u8  n2win;
-       u8  n3win;
-       u8  nvc;
-       u8  pktlen;
-       u8  locaddr;
-       u8  remaddr;
-       u16 t1;
-       u16 t2;
-       u8  t21;
-       u8  npvc;
-       u8  t23;
-       u8  flags;
-} PACKED;
-
-struct cycx_x25_stats {
-       u16 rx_crc_errors;
-       u16 rx_over_errors;
-       u16 n2_tx_frames;
-       u16 n2_rx_frames;
-       u16 tx_timeouts;
-       u16 rx_timeouts;
-       u16 n3_tx_packets;
-       u16 n3_rx_packets;
-       u16 tx_aborts;
-       u16 rx_aborts;
-} PACKED;
-#endif /* _CYCX_X25_H */
index 8e6c20af11a2c835b2489875513845161abb362c..e1e68da6f35c2edd71a08c47ddede967c90db3f9 100644 (file)
@@ -194,6 +194,9 @@ static inline char *mc_event_error_type(const unsigned int err_type)
  * @MEM_DDR3:          DDR3 RAM
  * @MEM_RDDR3:         Registered DDR3 RAM
  *                     This is a variant of the DDR3 memories.
+ * @MEM_DDR4:          DDR4 RAM
+ * @MEM_RDDR4:         Registered DDR4 RAM
+ *                     This is a variant of the DDR4 memories.
  */
 enum mem_type {
        MEM_EMPTY = 0,
@@ -213,6 +216,8 @@ enum mem_type {
        MEM_XDR,
        MEM_DDR3,
        MEM_RDDR3,
+       MEM_DDR4,
+       MEM_RDDR4,
 };
 
 #define MEM_FLAG_EMPTY         BIT(MEM_EMPTY)
index 9c5529dc6d0776b83888a3e77c0268e00e8f6585..733980fce8e30d6ddd2b442d407a3fac877a759a 100644 (file)
@@ -29,6 +29,7 @@
 #include <asm/bitsperlong.h>
 
 #ifdef __KERNEL__
+u32 eth_get_headlen(void *data, unsigned int max_len);
 __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev);
 extern const struct header_ops eth_header_ops;
 
index e658229fee39c17ea8673eadcf7b49cfdce508e1..c1a2d60dfb82769c42b65dc2adc324517ed7e79c 100644 (file)
@@ -257,6 +257,10 @@ struct ethtool_ops {
                                     struct ethtool_eeprom *, u8 *);
        int     (*get_eee)(struct net_device *, struct ethtool_eee *);
        int     (*set_eee)(struct net_device *, struct ethtool_eee *);
+       int     (*get_tunable)(struct net_device *,
+                              const struct ethtool_tunable *, void *);
+       int     (*set_tunable)(struct net_device *,
+                              const struct ethtool_tunable *, const void *);
 
 
 };
index 6ff0b0b42d47d7d6f719a3c2f5f6b5f5f2e16167..08ed2b0a96e6aef0ada70da633322f36a8acfe7e 100644 (file)
@@ -24,6 +24,9 @@
 #define NULL_ADDR              ((block_t)0)    /* used as block_t addresses */
 #define NEW_ADDR               ((block_t)-1)   /* used as block_t addresses */
 
+/* 0, 1(node nid), 2(meta nid) are reserved node id */
+#define F2FS_RESERVED_NODE_NUM         3
+
 #define F2FS_ROOT_INO(sbi)     (sbi->root_ino_num)
 #define F2FS_NODE_INO(sbi)     (sbi->node_ino_num)
 #define F2FS_META_INO(sbi)     (sbi->meta_ino_num)
@@ -87,6 +90,8 @@ struct f2fs_super_block {
 #define CP_ORPHAN_PRESENT_FLAG 0x00000002
 #define CP_UMOUNT_FLAG         0x00000001
 
+#define F2FS_CP_PACKS          2       /* # of checkpoint packs */
+
 struct f2fs_checkpoint {
        __le64 checkpoint_ver;          /* checkpoint block version number */
        __le64 user_block_count;        /* # of user blocks */
@@ -123,6 +128,9 @@ struct f2fs_checkpoint {
  */
 #define F2FS_ORPHANS_PER_BLOCK 1020
 
+#define GET_ORPHAN_BLOCKS(n)   ((n + F2FS_ORPHANS_PER_BLOCK - 1) / \
+                                       F2FS_ORPHANS_PER_BLOCK)
+
 struct f2fs_orphan_block {
        __le32 ino[F2FS_ORPHANS_PER_BLOCK];     /* inode numbers */
        __le32 reserved;        /* reserved */
@@ -144,6 +152,7 @@ struct f2fs_extent {
 #define F2FS_NAME_LEN          255
 #define F2FS_INLINE_XATTR_ADDRS        50      /* 200 bytes for inline xattrs */
 #define DEF_ADDRS_PER_INODE    923     /* Address Pointers in an Inode */
+#define DEF_NIDS_PER_INODE     5       /* Node IDs in an Inode */
 #define ADDRS_PER_INODE(fi)    addrs_per_inode(fi)
 #define ADDRS_PER_BLOCK                1018    /* Address Pointers in a Direct Block */
 #define NIDS_PER_BLOCK         1018    /* Node IDs in an Indirect Block */
@@ -163,8 +172,9 @@ struct f2fs_extent {
 #define MAX_INLINE_DATA                (sizeof(__le32) * (DEF_ADDRS_PER_INODE - \
                                                F2FS_INLINE_XATTR_ADDRS - 1))
 
-#define INLINE_DATA_OFFSET     (PAGE_CACHE_SIZE - sizeof(struct node_footer) \
-                       - sizeof(__le32) * (DEF_ADDRS_PER_INODE + 5 - 1))
+#define INLINE_DATA_OFFSET     (PAGE_CACHE_SIZE - sizeof(struct node_footer) -\
+                               sizeof(__le32) * (DEF_ADDRS_PER_INODE + \
+                               DEF_NIDS_PER_INODE - 1))
 
 struct f2fs_inode {
        __le16 i_mode;                  /* file mode */
@@ -194,7 +204,7 @@ struct f2fs_inode {
 
        __le32 i_addr[DEF_ADDRS_PER_INODE];     /* Pointers to data blocks */
 
-       __le32 i_nid[5];                /* direct(2), indirect(2),
+       __le32 i_nid[DEF_NIDS_PER_INODE];       /* direct(2), indirect(2),
                                                double_indirect(1) node id */
 } __packed;
 
index a5227ab8ccb17ebd4cf9ed7a55f80c352a2d6fb3..4b59edead908cbd3b3829c8d9a293d4e42d12e82 100644 (file)
@@ -9,53 +9,12 @@
 #include <linux/skbuff.h>
 #include <linux/workqueue.h>
 #include <uapi/linux/filter.h>
+#include <asm/cacheflush.h>
+#include <uapi/linux/bpf.h>
 
-/* 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 */
-
-/* Register numbers */
-enum {
-       BPF_REG_0 = 0,
-       BPF_REG_1,
-       BPF_REG_2,
-       BPF_REG_3,
-       BPF_REG_4,
-       BPF_REG_5,
-       BPF_REG_6,
-       BPF_REG_7,
-       BPF_REG_8,
-       BPF_REG_9,
-       BPF_REG_10,
-       __MAX_BPF_REG,
-};
-
-/* BPF has 10 general purpose 64-bit registers and stack frame. */
-#define MAX_BPF_REG    __MAX_BPF_REG
+struct sk_buff;
+struct sock;
+struct seccomp_data;
 
 /* ArgX, context and stack frame pointer register positions. Note,
  * Arg1, Arg2, Arg3, etc are used as argument mappings of function
@@ -161,6 +120,24 @@ enum {
                .off   = 0,                                     \
                .imm   = IMM })
 
+/* BPF_LD_IMM64 macro encodes single 'load 64-bit immediate' insn */
+#define BPF_LD_IMM64(DST, IMM)                                 \
+       BPF_LD_IMM64_RAW(DST, 0, IMM)
+
+#define BPF_LD_IMM64_RAW(DST, SRC, IMM)                                \
+       ((struct bpf_insn) {                                    \
+               .code  = BPF_LD | BPF_DW | BPF_IMM,             \
+               .dst_reg = DST,                                 \
+               .src_reg = SRC,                                 \
+               .off   = 0,                                     \
+               .imm   = (__u32) (IMM) }),                      \
+       ((struct bpf_insn) {                                    \
+               .code  = 0, /* zero is reserved opcode */       \
+               .dst_reg = 0,                                   \
+               .src_reg = 0,                                   \
+               .off   = 0,                                     \
+               .imm   = ((__u64) (IMM)) >> 32 })
+
 /* Short form of mov based on type, BPF_X: dst_reg = src_reg, BPF_K: dst_reg = imm32 */
 
 #define BPF_MOV64_RAW(TYPE, DST, SRC, IMM)                     \
@@ -299,14 +276,6 @@ enum {
 #define SK_RUN_FILTER(filter, ctx) \
        (*filter->prog->bpf_func)(ctx, filter->prog->insnsi)
 
-struct bpf_insn {
-       __u8    code;           /* opcode */
-       __u8    dst_reg:4;      /* dest register */
-       __u8    src_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 {
@@ -320,20 +289,28 @@ struct sock_fprog_kern {
        struct sock_filter      *filter;
 };
 
-struct sk_buff;
-struct sock;
-struct seccomp_data;
+struct bpf_binary_header {
+       unsigned int pages;
+       u8 image[];
+};
+
+struct bpf_work_struct {
+       struct bpf_prog *prog;
+       struct work_struct work;
+};
 
 struct bpf_prog {
-       u32                     jited:1,        /* Is our filter JIT'ed? */
-                               len:31;         /* Number of filter blocks */
+       u16                     pages;          /* Number of allocated pages */
+       bool                    jited;          /* Is our filter JIT'ed? */
+       u32                     len;            /* Number of filter blocks */
        struct sock_fprog_kern  *orig_prog;     /* Original BPF program */
+       struct bpf_work_struct  *work;          /* Deferred free work struct */
        unsigned int            (*bpf_func)(const struct sk_buff *skb,
                                            const struct bpf_insn *filter);
+       /* Instructions for interpreter */
        union {
                struct sock_filter      insns[0];
                struct bpf_insn         insnsi[0];
-               struct work_struct      work;
        };
 };
 
@@ -353,6 +330,26 @@ static inline unsigned int bpf_prog_size(unsigned int proglen)
 
 #define bpf_classic_proglen(fprog) (fprog->len * sizeof(fprog->filter[0]))
 
+#ifdef CONFIG_DEBUG_SET_MODULE_RONX
+static inline void bpf_prog_lock_ro(struct bpf_prog *fp)
+{
+       set_memory_ro((unsigned long)fp, fp->pages);
+}
+
+static inline void bpf_prog_unlock_ro(struct bpf_prog *fp)
+{
+       set_memory_rw((unsigned long)fp, fp->pages);
+}
+#else
+static inline void bpf_prog_lock_ro(struct bpf_prog *fp)
+{
+}
+
+static inline void bpf_prog_unlock_ro(struct bpf_prog *fp)
+{
+}
+#endif /* CONFIG_DEBUG_SET_MODULE_RONX */
+
 int sk_filter(struct sock *sk, struct sk_buff *skb);
 
 void bpf_prog_select_runtime(struct bpf_prog *fp);
@@ -361,6 +358,25 @@ void bpf_prog_free(struct bpf_prog *fp);
 int bpf_convert_filter(struct sock_filter *prog, int len,
                       struct bpf_insn *new_prog, int *new_len);
 
+struct bpf_prog *bpf_prog_alloc(unsigned int size, gfp_t gfp_extra_flags);
+struct bpf_prog *bpf_prog_realloc(struct bpf_prog *fp_old, unsigned int size,
+                                 gfp_t gfp_extra_flags);
+void __bpf_prog_free(struct bpf_prog *fp);
+
+typedef void (*bpf_jit_fill_hole_t)(void *area, unsigned int size);
+
+struct bpf_binary_header *
+bpf_jit_binary_alloc(unsigned int proglen, u8 **image_ptr,
+                    unsigned int alignment,
+                    bpf_jit_fill_hole_t bpf_fill_ill_insns);
+void bpf_jit_binary_free(struct bpf_binary_header *hdr);
+
+static inline void bpf_prog_unlock_free(struct bpf_prog *fp)
+{
+       bpf_prog_unlock_ro(fp);
+       __bpf_prog_free(fp);
+}
+
 int bpf_prog_create(struct bpf_prog **pfp, struct sock_fprog_kern *fprog);
 void bpf_prog_destroy(struct bpf_prog *fp);
 
@@ -450,7 +466,7 @@ static inline void bpf_jit_compile(struct bpf_prog *fp)
 
 static inline void bpf_jit_free(struct bpf_prog *fp)
 {
-       kfree(fp);
+       bpf_prog_unlock_free(fp);
 }
 #endif /* CONFIG_BPF_JIT */
 
index 6bb5e3f2a3b40741363838f6916db7886af16fe0..f0b0edbf55a94e4e4594ca65270e80bacd2e8f61 100644 (file)
@@ -102,6 +102,15 @@ enum {
        FTRACE_OPS_FL_DELETED                   = 1 << 8,
 };
 
+#ifdef CONFIG_DYNAMIC_FTRACE
+/* The hash used to know what functions callbacks trace */
+struct ftrace_ops_hash {
+       struct ftrace_hash              *notrace_hash;
+       struct ftrace_hash              *filter_hash;
+       struct mutex                    regex_lock;
+};
+#endif
+
 /*
  * Note, ftrace_ops can be referenced outside of RCU protection.
  * (Although, for perf, the control ops prevent that). If ftrace_ops is
@@ -121,10 +130,9 @@ struct ftrace_ops {
        int __percpu                    *disabled;
 #ifdef CONFIG_DYNAMIC_FTRACE
        int                             nr_trampolines;
-       struct ftrace_hash              *notrace_hash;
-       struct ftrace_hash              *filter_hash;
+       struct ftrace_ops_hash          local_hash;
+       struct ftrace_ops_hash          *func_hash;
        struct ftrace_hash              *tramp_hash;
-       struct mutex                    regex_lock;
        unsigned long                   trampoline;
 #endif
 };
index b7ce0c64c6f3186e4acf37857db3ed3a8390b1e7..12f146fa660434731df9ed2d8c2f6929dcc46217 100644 (file)
@@ -16,8 +16,6 @@ struct device;
  */
 struct gpio_desc;
 
-#ifdef CONFIG_GPIOLIB
-
 #define GPIOD_FLAGS_BIT_DIR_SET                BIT(0)
 #define GPIOD_FLAGS_BIT_DIR_OUT                BIT(1)
 #define GPIOD_FLAGS_BIT_DIR_VAL                BIT(2)
@@ -34,64 +32,38 @@ enum gpiod_flags {
                          GPIOD_FLAGS_BIT_DIR_VAL,
 };
 
+#ifdef CONFIG_GPIOLIB
+
 /* Acquire and dispose GPIOs */
 struct gpio_desc *__must_check __gpiod_get(struct device *dev,
                                         const char *con_id,
                                         enum gpiod_flags flags);
-#define __gpiod_get(dev, con_id, flags, ...) __gpiod_get(dev, con_id, flags)
-#define gpiod_get(varargs...) __gpiod_get(varargs, 0)
 struct gpio_desc *__must_check __gpiod_get_index(struct device *dev,
                                               const char *con_id,
                                               unsigned int idx,
                                               enum gpiod_flags flags);
-#define __gpiod_get_index(dev, con_id, index, flags, ...)              \
-       __gpiod_get_index(dev, con_id, index, flags)
-#define gpiod_get_index(varargs...) __gpiod_get_index(varargs, 0)
 struct gpio_desc *__must_check __gpiod_get_optional(struct device *dev,
                                                  const char *con_id,
                                                  enum gpiod_flags flags);
-#define __gpiod_get_optional(dev, con_id, flags, ...)                  \
-       __gpiod_get_optional(dev, con_id, flags)
-#define gpiod_get_optional(varargs...) __gpiod_get_optional(varargs, 0)
 struct gpio_desc *__must_check __gpiod_get_index_optional(struct device *dev,
                                                        const char *con_id,
                                                        unsigned int index,
                                                        enum gpiod_flags flags);
-#define __gpiod_get_index_optional(dev, con_id, index, flags, ...)     \
-       __gpiod_get_index_optional(dev, con_id, index, flags)
-#define gpiod_get_index_optional(varargs...)                           \
-       __gpiod_get_index_optional(varargs, 0)
-
 void gpiod_put(struct gpio_desc *desc);
 
 struct gpio_desc *__must_check __devm_gpiod_get(struct device *dev,
                                              const char *con_id,
                                              enum gpiod_flags flags);
-#define __devm_gpiod_get(dev, con_id, flags, ...)                      \
-       __devm_gpiod_get(dev, con_id, flags)
-#define devm_gpiod_get(varargs...) __devm_gpiod_get(varargs, 0)
 struct gpio_desc *__must_check __devm_gpiod_get_index(struct device *dev,
                                                    const char *con_id,
                                                    unsigned int idx,
                                                    enum gpiod_flags flags);
-#define __devm_gpiod_get_index(dev, con_id, index, flags, ...)         \
-       __devm_gpiod_get_index(dev, con_id, index, flags)
-#define devm_gpiod_get_index(varargs...) __devm_gpiod_get_index(varargs, 0)
 struct gpio_desc *__must_check __devm_gpiod_get_optional(struct device *dev,
                                                       const char *con_id,
                                                       enum gpiod_flags flags);
-#define __devm_gpiod_get_optional(dev, con_id, flags, ...)             \
-       __devm_gpiod_get_optional(dev, con_id, flags)
-#define devm_gpiod_get_optional(varargs...)                            \
-       __devm_gpiod_get_optional(varargs, 0)
 struct gpio_desc *__must_check
 __devm_gpiod_get_index_optional(struct device *dev, const char *con_id,
                              unsigned int index, enum gpiod_flags flags);
-#define __devm_gpiod_get_index_optional(dev, con_id, index, flags, ...)        \
-       __devm_gpiod_get_index_optional(dev, con_id, index, flags)
-#define devm_gpiod_get_index_optional(varargs...)                      \
-       __devm_gpiod_get_index_optional(varargs, 0)
-
 void devm_gpiod_put(struct device *dev, struct gpio_desc *desc);
 
 int gpiod_get_direction(const struct gpio_desc *desc);
@@ -124,27 +96,31 @@ int desc_to_gpio(const struct gpio_desc *desc);
 
 #else /* CONFIG_GPIOLIB */
 
-static inline struct gpio_desc *__must_check gpiod_get(struct device *dev,
-                                                      const char *con_id)
+static inline struct gpio_desc *__must_check __gpiod_get(struct device *dev,
+                                               const char *con_id,
+                                               enum gpiod_flags flags)
 {
        return ERR_PTR(-ENOSYS);
 }
-static inline struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
-                                                            const char *con_id,
-                                                            unsigned int idx)
+static inline struct gpio_desc *__must_check
+__gpiod_get_index(struct device *dev,
+                 const char *con_id,
+                 unsigned int idx,
+                 enum gpiod_flags flags)
 {
        return ERR_PTR(-ENOSYS);
 }
 
 static inline struct gpio_desc *__must_check
-gpiod_get_optional(struct device *dev, const char *con_id)
+__gpiod_get_optional(struct device *dev, const char *con_id,
+                    enum gpiod_flags flags)
 {
        return ERR_PTR(-ENOSYS);
 }
 
 static inline struct gpio_desc *__must_check
-gpiod_get_index_optional(struct device *dev, const char *con_id,
-                        unsigned int index)
+__gpiod_get_index_optional(struct device *dev, const char *con_id,
+                          unsigned int index, enum gpiod_flags flags)
 {
        return ERR_PTR(-ENOSYS);
 }
@@ -157,28 +133,33 @@ static inline void gpiod_put(struct gpio_desc *desc)
        WARN_ON(1);
 }
 
-static inline struct gpio_desc *__must_check devm_gpiod_get(struct device *dev,
-                                                           const char *con_id)
+static inline struct gpio_desc *__must_check
+__devm_gpiod_get(struct device *dev,
+                const char *con_id,
+                enum gpiod_flags flags)
 {
        return ERR_PTR(-ENOSYS);
 }
 static inline
-struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev,
-                                                   const char *con_id,
-                                                   unsigned int idx)
+struct gpio_desc *__must_check
+__devm_gpiod_get_index(struct device *dev,
+                      const char *con_id,
+                      unsigned int idx,
+                      enum gpiod_flags flags)
 {
        return ERR_PTR(-ENOSYS);
 }
 
 static inline struct gpio_desc *__must_check
-devm_gpiod_get_optional(struct device *dev, const char *con_id)
+__devm_gpiod_get_optional(struct device *dev, const char *con_id,
+                         enum gpiod_flags flags)
 {
        return ERR_PTR(-ENOSYS);
 }
 
 static inline struct gpio_desc *__must_check
-devm_gpiod_get_index_optional(struct device *dev, const char *con_id,
-                             unsigned int index)
+__devm_gpiod_get_index_optional(struct device *dev, const char *con_id,
+                               unsigned int index, enum gpiod_flags flags)
 {
        return ERR_PTR(-ENOSYS);
 }
@@ -303,9 +284,43 @@ static inline int desc_to_gpio(const struct gpio_desc *desc)
        return -EINVAL;
 }
 
-
 #endif /* CONFIG_GPIOLIB */
 
+/*
+ * Vararg-hacks! This is done to transition the kernel to always pass
+ * the options flags argument to the below functions. During a transition
+ * phase these vararg macros make both old-and-newstyle code compile,
+ * but when all calls to the elder API are removed, these should go away
+ * and the __gpiod_get() etc functions above be renamed just gpiod_get()
+ * etc.
+ */
+#define __gpiod_get(dev, con_id, flags, ...) __gpiod_get(dev, con_id, flags)
+#define gpiod_get(varargs...) __gpiod_get(varargs, 0)
+#define __gpiod_get_index(dev, con_id, index, flags, ...)              \
+       __gpiod_get_index(dev, con_id, index, flags)
+#define gpiod_get_index(varargs...) __gpiod_get_index(varargs, 0)
+#define __gpiod_get_optional(dev, con_id, flags, ...)                  \
+       __gpiod_get_optional(dev, con_id, flags)
+#define gpiod_get_optional(varargs...) __gpiod_get_optional(varargs, 0)
+#define __gpiod_get_index_optional(dev, con_id, index, flags, ...)     \
+       __gpiod_get_index_optional(dev, con_id, index, flags)
+#define gpiod_get_index_optional(varargs...)                           \
+       __gpiod_get_index_optional(varargs, 0)
+#define __devm_gpiod_get(dev, con_id, flags, ...)                      \
+       __devm_gpiod_get(dev, con_id, flags)
+#define devm_gpiod_get(varargs...) __devm_gpiod_get(varargs, 0)
+#define __devm_gpiod_get_index(dev, con_id, index, flags, ...)         \
+       __devm_gpiod_get_index(dev, con_id, index, flags)
+#define devm_gpiod_get_index(varargs...) __devm_gpiod_get_index(varargs, 0)
+#define __devm_gpiod_get_optional(dev, con_id, flags, ...)             \
+       __devm_gpiod_get_optional(dev, con_id, flags)
+#define devm_gpiod_get_optional(varargs...)                            \
+       __devm_gpiod_get_optional(varargs, 0)
+#define __devm_gpiod_get_index_optional(dev, con_id, index, flags, ...)        \
+       __devm_gpiod_get_index_optional(dev, con_id, index, flags)
+#define devm_gpiod_get_index_optional(varargs...)                      \
+       __devm_gpiod_get_index_optional(varargs, 0)
+
 #if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_GPIO_SYSFS)
 
 int gpiod_export(struct gpio_desc *desc, bool direction_may_change);
index ea507665896cfa774cf3fe7226b9da77d7bc9622..a95efeb53a8b76da08450f47f614f9713dc89a9f 100644 (file)
@@ -577,16 +577,20 @@ static inline struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node
 }
 #endif /* CONFIG_OF */
 
-#ifdef CONFIG_I2C_ACPI
-int acpi_i2c_install_space_handler(struct i2c_adapter *adapter);
-void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter);
+#ifdef CONFIG_ACPI
 void acpi_i2c_register_devices(struct i2c_adapter *adap);
 #else
 static inline void acpi_i2c_register_devices(struct i2c_adapter *adap) { }
+#endif /* CONFIG_ACPI */
+
+#ifdef CONFIG_ACPI_I2C_OPREGION
+int acpi_i2c_install_space_handler(struct i2c_adapter *adapter);
+void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter);
+#else
 static inline void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter)
 { }
 static inline int acpi_i2c_install_space_handler(struct i2c_adapter *adapter)
 { return 0; }
-#endif
+#endif /* CONFIG_ACPI_I2C_OPREGION */
 
 #endif /* _LINUX_I2C_H */
diff --git a/include/linux/i82593.h b/include/linux/i82593.h
deleted file mode 100644 (file)
index afac5c7..0000000
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Definitions for Intel 82593 CSMA/CD Core LAN Controller
- * The definitions are taken from the 1992 users manual with Intel
- * order number 297125-001.
- *
- * /usr/src/pc/RCS/i82593.h,v 1.1 1996/07/17 15:23:12 root Exp
- *
- * Copyright 1994, Anders Klemets <klemets@it.kth.se>
- *
- * HISTORY
- * i82593.h,v
- * Revision 1.4  2005/11/4  09:15:00  baroniunas
- * Modified copyright with permission of author as follows:
- *
- *   "If I82539.H is the only file with my copyright statement
- *    that is included in the Source Forge project, then you have
- *    my approval to change the copyright statement to be a GPL
- *    license, in the way you proposed on October 10."
- *
- * Revision 1.1  1996/07/17 15:23:12  root
- * Initial revision
- *
- * Revision 1.3  1995/04/05  15:13:58  adj
- * Initial alpha release
- *
- * Revision 1.2  1994/06/16  23:57:31  klemets
- * Mirrored all the fields in the configuration block.
- *
- * Revision 1.1  1994/06/02  20:25:34  klemets
- * Initial revision
- *
- *
- */
-#ifndef        _I82593_H
-#define        _I82593_H
-
-/* Intel 82593 CSMA/CD Core LAN Controller */
-
-/* Port 0 Command Register definitions */
-
-/* Execution operations */
-#define OP0_NOP                        0       /* CHNL = 0 */
-#define OP0_SWIT_TO_PORT_1     0       /* CHNL = 1 */
-#define OP0_IA_SETUP           1
-#define OP0_CONFIGURE          2
-#define OP0_MC_SETUP           3
-#define OP0_TRANSMIT           4
-#define OP0_TDR                        5
-#define OP0_DUMP               6
-#define OP0_DIAGNOSE           7
-#define OP0_TRANSMIT_NO_CRC    9
-#define OP0_RETRANSMIT         12
-#define OP0_ABORT              13
-/* Reception operations */
-#define OP0_RCV_ENABLE         8
-#define OP0_RCV_DISABLE                10
-#define OP0_STOP_RCV           11
-/* Status pointer control operations */
-#define OP0_FIX_PTR            15      /* CHNL = 1 */
-#define OP0_RLS_PTR            15      /* CHNL = 0 */
-#define OP0_RESET              14
-
-#define CR0_CHNL               (1 << 4)        /* 0=Channel 0, 1=Channel 1 */
-#define CR0_STATUS_0           0x00
-#define CR0_STATUS_1           0x20
-#define CR0_STATUS_2           0x40
-#define CR0_STATUS_3           0x60
-#define CR0_INT_ACK            (1 << 7)        /* 0=No ack, 1=acknowledge */
-
-/* Port 0 Status Register definitions */
-
-#define SR0_NO_RESULT          0               /* dummy */
-#define SR0_EVENT_MASK         0x0f
-#define SR0_IA_SETUP_DONE      1
-#define SR0_CONFIGURE_DONE     2
-#define SR0_MC_SETUP_DONE      3
-#define SR0_TRANSMIT_DONE      4
-#define SR0_TDR_DONE           5
-#define SR0_DUMP_DONE          6
-#define SR0_DIAGNOSE_PASSED    7
-#define SR0_TRANSMIT_NO_CRC_DONE 9
-#define SR0_RETRANSMIT_DONE    12
-#define SR0_EXECUTION_ABORTED  13
-#define SR0_END_OF_FRAME       8
-#define SR0_RECEPTION_ABORTED  10
-#define SR0_DIAGNOSE_FAILED    15
-#define SR0_STOP_REG_HIT       11
-
-#define SR0_CHNL               (1 << 4)
-#define SR0_EXECUTION          (1 << 5)
-#define SR0_RECEPTION          (1 << 6)
-#define SR0_INTERRUPT          (1 << 7)
-#define SR0_BOTH_RX_TX         (SR0_EXECUTION | SR0_RECEPTION)
-
-#define SR3_EXEC_STATE_MASK    0x03
-#define SR3_EXEC_IDLE          0
-#define SR3_TX_ABORT_IN_PROGRESS 1
-#define SR3_EXEC_ACTIVE                2
-#define SR3_ABORT_IN_PROGRESS  3
-#define SR3_EXEC_CHNL          (1 << 2)
-#define SR3_STP_ON_NO_RSRC     (1 << 3)
-#define SR3_RCVING_NO_RSRC     (1 << 4)
-#define SR3_RCV_STATE_MASK     0x60
-#define SR3_RCV_IDLE           0x00
-#define SR3_RCV_READY          0x20
-#define SR3_RCV_ACTIVE         0x40
-#define SR3_RCV_STOP_IN_PROG   0x60
-#define SR3_RCV_CHNL           (1 << 7)
-
-/* Port 1 Command Register definitions */
-
-#define OP1_NOP                        0
-#define OP1_SWIT_TO_PORT_0     1
-#define OP1_INT_DISABLE                2
-#define OP1_INT_ENABLE         3
-#define OP1_SET_TS             5
-#define OP1_RST_TS             7
-#define OP1_POWER_DOWN         8
-#define OP1_RESET_RING_MNGMT   11
-#define OP1_RESET              14
-#define OP1_SEL_RST            15
-
-#define CR1_STATUS_4           0x00
-#define CR1_STATUS_5           0x20
-#define CR1_STATUS_6           0x40
-#define CR1_STOP_REG_UPDATE    (1 << 7)
-
-/* Receive frame status bits */
-
-#define        RX_RCLD                 (1 << 0)
-#define RX_IA_MATCH            (1 << 1)
-#define        RX_NO_AD_MATCH          (1 << 2)
-#define RX_NO_SFD              (1 << 3)
-#define RX_SRT_FRM             (1 << 7)
-#define RX_OVRRUN              (1 << 8)
-#define RX_ALG_ERR             (1 << 10)
-#define RX_CRC_ERR             (1 << 11)
-#define RX_LEN_ERR             (1 << 12)
-#define RX_RCV_OK              (1 << 13)
-#define RX_TYP_LEN             (1 << 15)
-
-/* Transmit status bits */
-
-#define TX_NCOL_MASK           0x0f
-#define TX_FRTL                        (1 << 4)
-#define TX_MAX_COL             (1 << 5)
-#define TX_HRT_BEAT            (1 << 6)
-#define TX_DEFER               (1 << 7)
-#define TX_UND_RUN             (1 << 8)
-#define TX_LOST_CTS            (1 << 9)
-#define TX_LOST_CRS            (1 << 10)
-#define TX_LTCOL               (1 << 11)
-#define TX_OK                  (1 << 13)
-#define TX_COLL                        (1 << 15)
-
-struct i82593_conf_block {
-  u_char fifo_limit : 4,
-        forgnesi   : 1,
-        fifo_32    : 1,
-        d6mod      : 1,
-        throttle_enb : 1;
-  u_char throttle   : 6,
-        cntrxint   : 1,
-        contin     : 1;
-  u_char addr_len   : 3,
-        acloc      : 1,
-        preamb_len : 2,
-        loopback   : 2;
-  u_char lin_prio   : 3,
-        tbofstop   : 1,
-        exp_prio   : 3,
-        bof_met    : 1;
-  u_char           : 4,
-        ifrm_spc   : 4;
-  u_char           : 5,
-        slottim_low : 3;
-  u_char slottim_hi : 3,
-                   : 1,
-        max_retr   : 4;
-  u_char prmisc     : 1,
-        bc_dis     : 1,
-                   : 1,
-        crs_1      : 1,
-        nocrc_ins  : 1,
-        crc_1632   : 1,
-                   : 1,
-        crs_cdt    : 1;
-  u_char cs_filter  : 3,
-        crs_src    : 1,
-        cd_filter  : 3,
-                   : 1;
-  u_char           : 2,
-        min_fr_len : 6;
-  u_char lng_typ    : 1,
-        lng_fld    : 1,
-        rxcrc_xf   : 1,
-        artx       : 1,
-        sarec      : 1,
-        tx_jabber  : 1,        /* why is this called max_len in the manual? */
-        hash_1     : 1,
-        lbpkpol    : 1;
-  u_char           : 6,
-        fdx        : 1,
-                   : 1;
-  u_char dummy_6    : 6,       /* supposed to be ones */
-        mult_ia    : 1,
-        dis_bof    : 1;
-  u_char dummy_1    : 1,       /* supposed to be one */
-        tx_ifs_retrig : 2,
-        mc_all     : 1,
-        rcv_mon    : 2,
-        frag_acpt  : 1,
-        tstrttrs   : 1;
-  u_char fretx     : 1,
-        runt_eop   : 1,
-        hw_sw_pin  : 1,
-        big_endn   : 1,
-        syncrqs    : 1,
-        sttlen     : 1,
-        tx_eop     : 1,
-        rx_eop     : 1;
-  u_char rbuf_size  : 5,
-        rcvstop    : 1,
-                   : 2;
-};
-
-#define I82593_MAX_MULTICAST_ADDRESSES 128     /* Hardware hashed filter */
-
-#endif /* _I82593_H */
index 63ab3873c5ed00ac6fa36e73892d4db709c13bf0..8018c915ee632d90b5076b49325d59760de3ab34 100644 (file)
@@ -838,6 +838,16 @@ enum ieee80211_vht_opmode_bits {
 
 #define WLAN_SA_QUERY_TR_ID_LEN 2
 
+/**
+ * struct ieee80211_tpc_report_ie
+ *
+ * This structure refers to "TPC Report element"
+ */
+struct ieee80211_tpc_report_ie {
+       u8 tx_power;
+       u8 link_margin;
+} __packed;
+
 struct ieee80211_mgmt {
        __le16 frame_control;
        __le16 duration;
@@ -973,6 +983,13 @@ struct ieee80211_mgmt {
                                        u8 action_code;
                                        u8 operating_mode;
                                } __packed vht_opmode_notif;
+                               struct {
+                                       u8 action_code;
+                                       u8 dialog_token;
+                                       u8 tpc_elem_id;
+                                       u8 tpc_elem_length;
+                                       struct ieee80211_tpc_report_ie tpc;
+                               } __packed tpc_report;
                        } u;
                } __packed action;
        } u;
@@ -1865,6 +1882,7 @@ enum ieee80211_category {
        WLAN_CATEGORY_DLS = 2,
        WLAN_CATEGORY_BACK = 3,
        WLAN_CATEGORY_PUBLIC = 4,
+       WLAN_CATEGORY_RADIO_MEASUREMENT = 5,
        WLAN_CATEGORY_HT = 7,
        WLAN_CATEGORY_SA_QUERY = 8,
        WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION = 9,
@@ -2378,4 +2396,51 @@ static inline bool ieee80211_check_tim(const struct ieee80211_tim_ie *tim,
 #define TU_TO_JIFFIES(x)       (usecs_to_jiffies((x) * 1024))
 #define TU_TO_EXP_TIME(x)      (jiffies + TU_TO_JIFFIES(x))
 
+/**
+ * ieee80211_action_contains_tpc - checks if the frame contains TPC element
+ * @skb: the skb containing the frame, length will be checked
+ *
+ * This function checks if it's either TPC report action frame or Link
+ * Measurement report action frame as defined in IEEE Std. 802.11-2012 8.5.2.5
+ * and 8.5.7.5 accordingly.
+ */
+static inline bool ieee80211_action_contains_tpc(struct sk_buff *skb)
+{
+       struct ieee80211_mgmt *mgmt = (void *)skb->data;
+
+       if (!ieee80211_is_action(mgmt->frame_control))
+               return false;
+
+       if (skb->len < IEEE80211_MIN_ACTION_SIZE +
+                      sizeof(mgmt->u.action.u.tpc_report))
+               return false;
+
+       /*
+        * TPC report - check that:
+        * category = 0 (Spectrum Management) or 5 (Radio Measurement)
+        * spectrum management action = 3 (TPC/Link Measurement report)
+        * TPC report EID = 35
+        * TPC report element length = 2
+        *
+        * The spectrum management's tpc_report struct is used here both for
+        * parsing tpc_report and radio measurement's link measurement report
+        * frame, since the relevant part is identical in both frames.
+        */
+       if (mgmt->u.action.category != WLAN_CATEGORY_SPECTRUM_MGMT &&
+           mgmt->u.action.category != WLAN_CATEGORY_RADIO_MEASUREMENT)
+               return false;
+
+       /* both spectrum mgmt and link measurement have same action code */
+       if (mgmt->u.action.u.tpc_report.action_code !=
+           WLAN_ACTION_SPCT_TPC_RPRT)
+               return false;
+
+       if (mgmt->u.action.u.tpc_report.tpc_elem_id != WLAN_EID_TPC_REPORT ||
+           mgmt->u.action.u.tpc_report.tpc_elem_length !=
+           sizeof(struct ieee80211_tpc_report_ie))
+               return false;
+
+       return true;
+}
+
 #endif /* LINUX_IEEE80211_H */
index f47550d75f85fddd53186c92f0e1383c8f693b90..2c677afeea4782c96b79d0d8ede4846d87783b99 100644 (file)
@@ -39,6 +39,7 @@ static inline struct igmpv3_query *
 
 extern int sysctl_igmp_max_memberships;
 extern int sysctl_igmp_max_msf;
+extern int sysctl_igmp_qrv;
 
 struct ip_sf_socklist {
        unsigned int            sl_max;
index 1b1dfa80d9fffe2b28cfd5f02c64a3bad3c932d4..f583ff63977608827cd2e7e56fe4f344cdf4d7ed 100644 (file)
@@ -105,6 +105,7 @@ void input_mt_report_slot_state(struct input_dev *dev,
 
 void input_mt_report_finger_count(struct input_dev *dev, int count);
 void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count);
+void input_mt_drop_unused(struct input_dev *dev);
 
 void input_mt_sync_frame(struct input_dev *dev);
 
index d5b50a19463c0c1a43eaed5fb8dff41789f8f472..0dae71e9971c434cef33c13572dbd13018f3604e 100644 (file)
@@ -159,7 +159,11 @@ typedef struct journal_header_s
  * journal_block_tag (in the descriptor).  The other h_chksum* fields are
  * not used.
  *
- * Checksum v1 and v2 are mutually exclusive features.
+ * If FEATURE_INCOMPAT_CSUM_V3 is set, the descriptor block uses
+ * journal_block_tag3_t to store a full 32-bit checksum.  Everything else
+ * is the same as v2.
+ *
+ * Checksum v1, v2, and v3 are mutually exclusive features.
  */
 struct commit_header {
        __be32          h_magic;
@@ -179,6 +183,14 @@ struct commit_header {
  * raw struct shouldn't be used for pointer math or sizeof() - use
  * journal_tag_bytes(journal) instead to compute this.
  */
+typedef struct journal_block_tag3_s
+{
+       __be32          t_blocknr;      /* The on-disk block number */
+       __be32          t_flags;        /* See below */
+       __be32          t_blocknr_high; /* most-significant high 32bits. */
+       __be32          t_checksum;     /* crc32c(uuid+seq+block) */
+} journal_block_tag3_t;
+
 typedef struct journal_block_tag_s
 {
        __be32          t_blocknr;      /* The on-disk block number */
@@ -187,9 +199,6 @@ typedef struct journal_block_tag_s
        __be32          t_blocknr_high; /* most-significant high 32bits. */
 } journal_block_tag_t;
 
-#define JBD2_TAG_SIZE32 (offsetof(journal_block_tag_t, t_blocknr_high))
-#define JBD2_TAG_SIZE64 (sizeof(journal_block_tag_t))
-
 /* Tail of descriptor block, for checksumming */
 struct jbd2_journal_block_tail {
        __be32          t_checksum;     /* crc32c(uuid+descr_block) */
@@ -284,6 +293,7 @@ typedef struct journal_superblock_s
 #define JBD2_FEATURE_INCOMPAT_64BIT            0x00000002
 #define JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT     0x00000004
 #define JBD2_FEATURE_INCOMPAT_CSUM_V2          0x00000008
+#define JBD2_FEATURE_INCOMPAT_CSUM_V3          0x00000010
 
 /* Features known to this kernel version: */
 #define JBD2_KNOWN_COMPAT_FEATURES     JBD2_FEATURE_COMPAT_CHECKSUM
@@ -291,7 +301,8 @@ typedef struct journal_superblock_s
 #define JBD2_KNOWN_INCOMPAT_FEATURES   (JBD2_FEATURE_INCOMPAT_REVOKE | \
                                        JBD2_FEATURE_INCOMPAT_64BIT | \
                                        JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT | \
-                                       JBD2_FEATURE_INCOMPAT_CSUM_V2)
+                                       JBD2_FEATURE_INCOMPAT_CSUM_V2 | \
+                                       JBD2_FEATURE_INCOMPAT_CSUM_V3)
 
 #ifdef __KERNEL__
 
@@ -1296,6 +1307,15 @@ static inline int tid_geq(tid_t x, tid_t y)
 extern int jbd2_journal_blocks_per_page(struct inode *inode);
 extern size_t journal_tag_bytes(journal_t *journal);
 
+static inline int jbd2_journal_has_csum_v2or3(journal_t *journal)
+{
+       if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2) ||
+           JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V3))
+               return 1;
+
+       return 0;
+}
+
 /*
  * We reserve t_outstanding_credits >> JBD2_CONTROL_BLOCKS_SHIFT for
  * transaction control blocks.
index 6a599dce7f9d4678e4f6f7f082514308f0636942..e436864721971c81383a323bf3951e19632475a0 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/list.h>
 #include <linux/spinlock.h>
 #include <linux/rwsem.h>
+#include <linux/timer.h>
 #include <linux/workqueue.h>
 
 struct device;
@@ -68,7 +69,7 @@ struct led_classdev {
        const char              *default_trigger;       /* Trigger to use */
 
        unsigned long            blink_delay_on, blink_delay_off;
-       struct delayed_work      blink_work;
+       struct timer_list        blink_timer;
        int                      blink_brightness;
 
        struct work_struct      set_brightness_work;
index 071f6b234604cf770ebfab55e1ec61392e364a83..1befd8df9cfc98d9dc190ed0db98f16f15810cfd 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/completion.h>
 #include <linux/radix-tree.h>
 #include <linux/cpu_rmap.h>
+#include <linux/crash_dump.h>
 
 #include <linux/atomic.h>
 
@@ -1196,6 +1197,9 @@ int mlx4_map_sw_to_hw_steering_id(struct mlx4_dev *dev,
                                  enum mlx4_net_trans_rule_id id);
 int mlx4_hw_rule_sz(struct mlx4_dev *dev, enum mlx4_net_trans_rule_id id);
 
+int mlx4_tunnel_steer_add(struct mlx4_dev *dev, unsigned char *addr,
+                         int port, int qpn, u16 prio, u64 *reg_id);
+
 void mlx4_sync_pkey_table(struct mlx4_dev *dev, int slave, int port,
                          int i, int val);
 
@@ -1275,7 +1279,7 @@ int mlx4_mr_rereg_mem_write(struct mlx4_dev *dev, struct mlx4_mr *mr,
 /* Returns true if running in low memory profile (kdump kernel) */
 static inline bool mlx4_low_memory_profile(void)
 {
-       return reset_devices;
+       return is_kdump_kernel();
 }
 
 #endif /* MLX4_DEVICE_H */
index 3083c53e027049196f8f18561cd1d13f51b72a07..c300db3ae2852b88321c618daeb10bdc4eb5b21b 100644 (file)
@@ -949,7 +949,7 @@ static inline int jedec_feature(struct nand_chip *chip)
                : 0;
 }
 
-/**
+/*
  * struct nand_sdr_timings - SDR NAND chip timings
  *
  * This struct defines the timing requirements of a SDR NAND chip.
index 38377392d08261291ceb1fcd177718484e05581c..ba72f6baae1a9030318f6d769bc513e9682d9bf2 100644 (file)
@@ -1747,6 +1747,12 @@ struct netdev_queue *netdev_get_tx_queue(const struct net_device *dev,
        return &dev->_tx[index];
 }
 
+static inline struct netdev_queue *skb_get_tx_queue(const struct net_device *dev,
+                                                   const struct sk_buff *skb)
+{
+       return netdev_get_tx_queue(dev, skb_get_queue_mapping(skb));
+}
+
 static inline void netdev_for_each_tx_queue(struct net_device *dev,
                                            void (*f)(struct net_device *,
                                                      struct netdev_queue *,
@@ -1781,24 +1787,13 @@ void dev_net_set(struct net_device *dev, struct net *net)
 #endif
 }
 
-static inline bool netdev_uses_dsa_tags(struct net_device *dev)
+static inline bool netdev_uses_dsa(struct net_device *dev)
 {
-#ifdef CONFIG_NET_DSA_TAG_DSA
+#ifdef CONFIG_NET_DSA
        if (dev->dsa_ptr != NULL)
-               return dsa_uses_dsa_tags(dev->dsa_ptr);
+               return dsa_uses_tagged_protocol(dev->dsa_ptr);
 #endif
-
-       return 0;
-}
-
-static inline bool netdev_uses_trailer_tags(struct net_device *dev)
-{
-#ifdef CONFIG_NET_DSA_TAG_TRAILER
-       if (dev->dsa_ptr != NULL)
-               return dsa_uses_trailer_tags(dev->dsa_ptr);
-#endif
-
-       return 0;
+       return false;
 }
 
 /**
@@ -1883,7 +1878,13 @@ struct napi_gro_cb {
        u16     proto;
 
        /* Used in udp_gro_receive */
-       u16     udp_mark;
+       u8      udp_mark:1;
+
+       /* GRO checksum is valid */
+       u8      csum_valid:1;
+
+       /* Number of checksums via CHECKSUM_UNNECESSARY */
+       u8      csum_cnt:3;
 
        /* used to support CHECKSUM_COMPLETE for tunneling protocols */
        __wsum  csum;
@@ -1927,6 +1928,13 @@ struct udp_offload {
        struct offload_callbacks callbacks;
 };
 
+struct dsa_device_ops {
+       netdev_tx_t (*xmit)(struct sk_buff *skb, struct net_device *dev);
+       int (*rcv)(struct sk_buff *skb, struct net_device *dev,
+                  struct packet_type *pt, struct net_device *orig_dev);
+};
+
+
 /* often modified stats are per cpu, other are shared (netdev->stats) */
 struct pcpu_sw_netstats {
        u64     rx_packets;
@@ -1982,6 +1990,7 @@ struct pcpu_sw_netstats {
 #define NETDEV_CHANGEUPPER     0x0015
 #define NETDEV_RESEND_IGMP     0x0016
 #define NETDEV_PRECHANGEMTU    0x0017 /* notify before mtu change happened */
+#define NETDEV_CHANGEINFODATA  0x0018
 
 int register_netdevice_notifier(struct notifier_block *nb);
 int unregister_netdevice_notifier(struct notifier_block *nb);
@@ -2153,11 +2162,97 @@ static inline void *skb_gro_network_header(struct sk_buff *skb)
 static inline void skb_gro_postpull_rcsum(struct sk_buff *skb,
                                        const void *start, unsigned int len)
 {
-       if (skb->ip_summed == CHECKSUM_COMPLETE)
+       if (NAPI_GRO_CB(skb)->csum_valid)
                NAPI_GRO_CB(skb)->csum = csum_sub(NAPI_GRO_CB(skb)->csum,
                                                  csum_partial(start, len, 0));
 }
 
+/* GRO checksum functions. These are logical equivalents of the normal
+ * checksum functions (in skbuff.h) except that they operate on the GRO
+ * offsets and fields in sk_buff.
+ */
+
+__sum16 __skb_gro_checksum_complete(struct sk_buff *skb);
+
+static inline bool __skb_gro_checksum_validate_needed(struct sk_buff *skb,
+                                                     bool zero_okay,
+                                                     __sum16 check)
+{
+       return (skb->ip_summed != CHECKSUM_PARTIAL &&
+               NAPI_GRO_CB(skb)->csum_cnt == 0 &&
+               (!zero_okay || check));
+}
+
+static inline __sum16 __skb_gro_checksum_validate_complete(struct sk_buff *skb,
+                                                          __wsum psum)
+{
+       if (NAPI_GRO_CB(skb)->csum_valid &&
+           !csum_fold(csum_add(psum, NAPI_GRO_CB(skb)->csum)))
+               return 0;
+
+       NAPI_GRO_CB(skb)->csum = psum;
+
+       return __skb_gro_checksum_complete(skb);
+}
+
+static inline void skb_gro_incr_csum_unnecessary(struct sk_buff *skb)
+{
+       if (NAPI_GRO_CB(skb)->csum_cnt > 0) {
+               /* Consume a checksum from CHECKSUM_UNNECESSARY */
+               NAPI_GRO_CB(skb)->csum_cnt--;
+       } else {
+               /* Update skb for CHECKSUM_UNNECESSARY and csum_level when we
+                * verified a new top level checksum or an encapsulated one
+                * during GRO. This saves work if we fallback to normal path.
+                */
+               __skb_incr_checksum_unnecessary(skb);
+       }
+}
+
+#define __skb_gro_checksum_validate(skb, proto, zero_okay, check,      \
+                                   compute_pseudo)                     \
+({                                                                     \
+       __sum16 __ret = 0;                                              \
+       if (__skb_gro_checksum_validate_needed(skb, zero_okay, check))  \
+               __ret = __skb_gro_checksum_validate_complete(skb,       \
+                               compute_pseudo(skb, proto));            \
+       if (__ret)                                                      \
+               __skb_mark_checksum_bad(skb);                           \
+       else                                                            \
+               skb_gro_incr_csum_unnecessary(skb);                     \
+       __ret;                                                          \
+})
+
+#define skb_gro_checksum_validate(skb, proto, compute_pseudo)          \
+       __skb_gro_checksum_validate(skb, proto, false, 0, compute_pseudo)
+
+#define skb_gro_checksum_validate_zero_check(skb, proto, check,                \
+                                            compute_pseudo)            \
+       __skb_gro_checksum_validate(skb, proto, true, check, compute_pseudo)
+
+#define skb_gro_checksum_simple_validate(skb)                          \
+       __skb_gro_checksum_validate(skb, 0, false, 0, null_compute_pseudo)
+
+static inline bool __skb_gro_checksum_convert_check(struct sk_buff *skb)
+{
+       return (NAPI_GRO_CB(skb)->csum_cnt == 0 &&
+               !NAPI_GRO_CB(skb)->csum_valid);
+}
+
+static inline void __skb_gro_checksum_convert(struct sk_buff *skb,
+                                             __sum16 check, __wsum pseudo)
+{
+       NAPI_GRO_CB(skb)->csum = ~pseudo;
+       NAPI_GRO_CB(skb)->csum_valid = 1;
+}
+
+#define skb_gro_checksum_try_convert(skb, proto, check, compute_pseudo)        \
+do {                                                                   \
+       if (__skb_gro_checksum_convert_check(skb))                      \
+               __skb_gro_checksum_convert(skb, check,                  \
+                                          compute_pseudo(skb, proto)); \
+} while (0)
+
 static inline int dev_hard_header(struct sk_buff *skb, struct net_device *dev,
                                  unsigned short type,
                                  const void *daddr, const void *saddr,
@@ -2754,8 +2849,9 @@ int dev_set_mac_address(struct net_device *, struct sockaddr *);
 int dev_change_carrier(struct net_device *, bool new_carrier);
 int dev_get_phys_port_id(struct net_device *dev,
                         struct netdev_phys_port_id *ppid);
-int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
-                       struct netdev_queue *txq);
+struct sk_buff *validate_xmit_skb(struct sk_buff *skb, struct net_device *dev);
+struct sk_buff *dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
+                                   struct netdev_queue *txq, int *ret);
 int __dev_forward_skb(struct net_device *dev, struct sk_buff *skb);
 int dev_forward_skb(struct net_device *dev, struct sk_buff *skb);
 bool is_skb_forwardable(struct net_device *dev, struct sk_buff *skb);
@@ -3176,7 +3272,7 @@ static inline int __dev_uc_sync(struct net_device *dev,
 }
 
 /**
- *  __dev_uc_unsync - Remove synchonized addresses from device
+ *  __dev_uc_unsync - Remove synchronized addresses from device
  *  @dev:  device to sync
  *  @unsync: function to call if address should be removed
  *
@@ -3220,7 +3316,7 @@ static inline int __dev_mc_sync(struct net_device *dev,
 }
 
 /**
- *  __dev_mc_unsync - Remove synchonized addresses from device
+ *  __dev_mc_unsync - Remove synchronized addresses from device
  *  @dev:  device to sync
  *  @unsync: function to call if address should be removed
  *
@@ -3357,6 +3453,27 @@ int __init dev_proc_init(void);
 #define dev_proc_init() 0
 #endif
 
+static inline netdev_tx_t __netdev_start_xmit(const struct net_device_ops *ops,
+                                             struct sk_buff *skb, struct net_device *dev,
+                                             bool more)
+{
+       skb->xmit_more = more ? 1 : 0;
+       return ops->ndo_start_xmit(skb, dev);
+}
+
+static inline netdev_tx_t netdev_start_xmit(struct sk_buff *skb, struct net_device *dev,
+                                           struct netdev_queue *txq, bool more)
+{
+       const struct net_device_ops *ops = dev->netdev_ops;
+       int rc;
+
+       rc = __netdev_start_xmit(ops, skb, dev, more);
+       if (rc == NETDEV_TX_OK)
+               txq_trans_update(txq);
+
+       return rc;
+}
+
 int netdev_class_create_file_ns(struct class_attribute *class_attr,
                                const void *ns);
 void netdev_class_remove_file_ns(struct class_attribute *class_attr,
index 2077489f98873bcbe4ca083cd1f0eb1b99eeab5e..2517ece988209a611b324a0bb8ade2b566eeb645 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/in6.h>
 #include <linux/wait.h>
 #include <linux/list.h>
+#include <linux/static_key.h>
 #include <uapi/linux/netfilter.h>
 #ifdef CONFIG_NETFILTER
 static inline int NF_DROP_GETERR(int verdict)
@@ -99,9 +100,9 @@ void nf_unregister_sockopt(struct nf_sockopt_ops *reg);
 
 extern struct list_head nf_hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
 
-#if defined(CONFIG_JUMP_LABEL)
-#include <linux/static_key.h>
+#ifdef HAVE_JUMP_LABEL
 extern struct static_key nf_hooks_needed[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
+
 static inline bool nf_hooks_active(u_int8_t pf, unsigned int hook)
 {
        if (__builtin_constant_p(pf) &&
index 6ad2bbcad4050c12105778c3011b5196fcbf4b9e..6c3e06ee2fb7af63cc5a87314baec589631619af 100644 (file)
@@ -123,6 +123,7 @@ extern  int nfs_wait_on_request(struct nfs_page *);
 extern void nfs_unlock_request(struct nfs_page *req);
 extern void nfs_unlock_and_release_request(struct nfs_page *);
 extern int nfs_page_group_lock(struct nfs_page *, bool);
+extern void nfs_page_group_lock_wait(struct nfs_page *);
 extern void nfs_page_group_unlock(struct nfs_page *);
 extern bool nfs_page_group_sync_on_bit(struct nfs_page *, unsigned int);
 
diff --git a/include/linux/phonedev.h b/include/linux/phonedev.h
deleted file mode 100644 (file)
index 4269de9..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef __LINUX_PHONEDEV_H
-#define __LINUX_PHONEDEV_H
-
-#include <linux/types.h>
-
-#ifdef __KERNEL__
-
-#include <linux/poll.h>
-
-struct phone_device {
-       struct phone_device *next;
-       const struct file_operations *f_op;
-       int (*open) (struct phone_device *, struct file *);
-       int board;              /* Device private index */
-       int minor;
-};
-
-extern int phonedev_init(void);
-#define PHONE_MAJOR    100
-extern int phone_register_device(struct phone_device *, int unit);
-#define PHONE_UNIT_ANY -1
-extern void phone_unregister_device(struct phone_device *);
-
-#endif
-#endif
index ed39956b5613f98b95a5edd94bfb3f422abe71c7..d090cfcaa167fe33a4fc0e63562219a813f37c28 100644 (file)
@@ -597,6 +597,19 @@ static inline int phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum)
                            MII_ADDR_C45 | (devad << 16) | (regnum & 0xffff));
 }
 
+/**
+ * phy_read_mmd_indirect - reads data from the MMD registers
+ * @phydev: The PHY device bus
+ * @prtad: MMD Address
+ * @devad: MMD DEVAD
+ * @addr: PHY address on the MII bus
+ *
+ * Description: it reads data from the MMD registers (clause 22 to access to
+ * clause 45) of the specified phy address.
+ */
+int phy_read_mmd_indirect(struct phy_device *phydev, int prtad,
+                         int devad, int addr);
+
 /**
  * phy_read - Convenience function for reading a given PHY register
  * @phydev: the phy_device struct
@@ -668,6 +681,20 @@ static inline int phy_write_mmd(struct phy_device *phydev, int devad,
        return mdiobus_write(phydev->bus, phydev->addr, regnum, val);
 }
 
+/**
+ * phy_write_mmd_indirect - writes data to the MMD registers
+ * @phydev: The PHY device
+ * @prtad: MMD Address
+ * @devad: MMD DEVAD
+ * @addr: PHY address on the MII bus
+ * @data: data to write in the MMD register
+ *
+ * Description: Write data from the MMD registers of the specified
+ * phy address.
+ */
+void phy_write_mmd_indirect(struct phy_device *phydev, int prtad,
+                           int devad, int addr, u32 data);
+
 struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id,
                                     bool is_c45,
                                     struct phy_c45_device_ids *c45_ids);
index ae612acebb53d2f0bf121226afde877cb4d32f91..941138664c1db88c61e83fe53fdaf6fc31c73b7b 100644 (file)
@@ -18,6 +18,9 @@ extern int fixed_phy_register(unsigned int irq,
                              struct fixed_phy_status *status,
                              struct device_node *np);
 extern void fixed_phy_del(int phy_addr);
+extern int fixed_phy_set_link_update(struct phy_device *phydev,
+                       int (*link_update)(struct net_device *,
+                                          struct fixed_phy_status *));
 #else
 static inline int fixed_phy_add(unsigned int irq, int phy_id,
                                struct fixed_phy_status *status)
@@ -34,14 +37,12 @@ static inline int fixed_phy_del(int phy_addr)
 {
        return -ENODEV;
 }
-#endif /* CONFIG_FIXED_PHY */
-
-/*
- * This function issued only by fixed_phy-aware drivers, no need
- * protect it with #ifdef
- */
-extern int fixed_phy_set_link_update(struct phy_device *phydev,
+static inline int fixed_phy_set_link_update(struct phy_device *phydev,
                        int (*link_update)(struct net_device *,
-                                          struct fixed_phy_status *));
+                                          struct fixed_phy_status *))
+{
+       return -ENODEV;
+}
+#endif /* CONFIG_FIXED_PHY */
 
 #endif /* __PHY_FIXED_H */
index 660c029d694fce72c7f3b8d53c7703d21c85f54a..16ec262dfcc804a567910dad83bb3edbe72bdc74 100644 (file)
@@ -21,8 +21,17 @@ enum nand_io {
 };
 
 enum omap_ecc {
-       /* 1-bit  ECC calculation by GPMC, Error detection by Software */
-       OMAP_ECC_HAM1_CODE_HW = 0,
+       /*
+        * 1-bit ECC: calculation and correction by SW
+        * ECC stored at end of spare area
+        */
+       OMAP_ECC_HAM1_CODE_SW = 0,
+
+       /*
+        * 1-bit ECC: calculation by GPMC, Error detection by Software
+        * ECC layout compatible with ROM code layout
+        */
+       OMAP_ECC_HAM1_CODE_HW,
        /* 4-bit  ECC calculation by GPMC, Error detection by Software */
        OMAP_ECC_BCH4_CODE_HW_DETECTION_SW,
        /* 4-bit  ECC calculation by GPMC, Error detection by ELM */
index 7c1d252b20c08de0ec725976c67b6fc13326e2e0..ebc4c76ffb737bae3d9be1a6325752745254eaed 100644 (file)
@@ -60,7 +60,7 @@ struct generic_pm_domain {
        struct mutex lock;
        struct dev_power_governor *gov;
        struct work_struct power_off_work;
-       char *name;
+       const char *name;
        unsigned int in_progress;       /* Number of devices being suspended now */
        atomic_t sd_count;      /* Number of subdomains with power "on" */
        enum gpd_status status; /* Current state of the domain */
index 57fbbffd77a0406fe57ce2abb5c2a24d819c45f9..b05856e16b75be8b7dea5015a5a6ff6afcb021eb 100644 (file)
@@ -26,7 +26,7 @@ unsigned int get_random_int(void);
 unsigned long randomize_range(unsigned long start, unsigned long end, unsigned long len);
 
 u32 prandom_u32(void);
-void prandom_bytes(void *buf, int nbytes);
+void prandom_bytes(void *buf, size_t nbytes);
 void prandom_seed(u32 seed);
 void prandom_reseed_late(void);
 
@@ -35,7 +35,7 @@ struct rnd_state {
 };
 
 u32 prandom_u32_state(struct rnd_state *state);
-void prandom_bytes_state(struct rnd_state *state, void *buf, int nbytes);
+void prandom_bytes_state(struct rnd_state *state, void *buf, size_t nbytes);
 
 /**
  * prandom_u32_max - returns a pseudo-random number in interval [0, ep_ro)
index bbe03a1924c04182be79d128854557ebb262b6e3..4efa1ed8a2b0b92ebdd7160948e45b79b0e19fdf 100644 (file)
@@ -218,6 +218,8 @@ enum regulator_type {
  * @linear_min_sel: Minimal selector for starting linear mapping
  * @fixed_uV: Fixed voltage of rails.
  * @ramp_delay: Time to settle down after voltage change (unit: uV/us)
+ * @linear_ranges: A constant table of possible voltage ranges.
+ * @n_linear_ranges: Number of entries in the @linear_ranges table.
  * @volt_table: Voltage mapping table (if table based mapping)
  *
  * @vsel_reg: Register for selector when using regulator_regmap_X_voltage_
index 730e638c55899ba9bfff37a045386af5ee0f5cfe..0b08d05d470b56cacec467d5368810517d4a1752 100644 (file)
@@ -85,6 +85,7 @@ struct regulator_state {
  *           bootloader then it will be enabled when the constraints are
  *           applied.
  * @apply_uV: Apply the voltage constraint when initialising.
+ * @ramp_disable: Disable ramp delay when initialising or when setting voltage.
  *
  * @input_uV: Input voltage for regulator when supplied by another regulator.
  *
index 36826c0166c5f5af0d3a8e7601944f0e93946e09..fb298e9d6d3a8e75c280162f21e04c5112eebeac 100644 (file)
@@ -44,6 +44,7 @@ struct rhashtable;
  * @head_offset: Offset of rhash_head in struct to be hashed
  * @hash_rnd: Seed to use while hashing
  * @max_shift: Maximum number of shifts while expanding
+ * @min_shift: Minimum number of shifts while shrinking
  * @hashfn: Function to hash key
  * @obj_hashfn: Function to hash object
  * @grow_decision: If defined, may return true if table should expand
@@ -57,6 +58,7 @@ struct rhashtable_params {
        size_t                  head_offset;
        u32                     hash_rnd;
        size_t                  max_shift;
+       size_t                  min_shift;
        rht_hashfn_t            hashfn;
        rht_obj_hashfn_t        obj_hashfn;
        bool                    (*grow_decision)(const struct rhashtable *ht,
index 3d6003de4b0d4e4d367231cf3ee457cf612bf5aa..a1ba6a5ccdd62c2275eb63106d2fc9d78e4cee3c 100644 (file)
@@ -62,6 +62,7 @@ to_seqno_fence(struct fence *fence)
  * @context: the execution context this fence is a part of
  * @seqno_ofs: the offset within @sync_buf
  * @seqno: the sequence # to signal on
+ * @cond: fence wait condition
  * @ops: the fence_ops for operations on this seqno fence
  *
  * This function initializes a struct seqno_fence with passed parameters,
index abde271c18ae30989e6675708e70a6c9bb656300..07c9fdd0c1266a72f3c1a4536586b5109cbe4f27 100644 (file)
  *
  *   The hardware you're dealing with doesn't calculate the full checksum
  *   (as in CHECKSUM_COMPLETE), but it does parse headers and verify checksums
- *   for specific protocols e.g. TCP/UDP/SCTP, then, for such packets it will
- *   set CHECKSUM_UNNECESSARY if their checksums are okay. skb->csum is still
- *   undefined in this case though. It is a bad option, but, unfortunately,
- *   nowadays most vendors do this. Apparently with the secret goal to sell
- *   you new devices, when you will add new protocol to your host, f.e. IPv6 8)
+ *   for specific protocols. For such packets it will set CHECKSUM_UNNECESSARY
+ *   if their checksums are okay. skb->csum is still undefined in this case
+ *   though. It is a bad option, but, unfortunately, nowadays most vendors do
+ *   this. Apparently with the secret goal to sell you new devices, when you
+ *   will add new protocol to your host, f.e. IPv6 8)
+ *
+ *   CHECKSUM_UNNECESSARY is applicable to following protocols:
+ *     TCP: IPv6 and IPv4.
+ *     UDP: IPv4 and IPv6. A device may apply CHECKSUM_UNNECESSARY to a
+ *       zero UDP checksum for either IPv4 or IPv6, the networking stack
+ *       may perform further validation in this case.
+ *     GRE: only if the checksum is present in the header.
+ *     SCTP: indicates the CRC in SCTP header has been validated.
+ *
+ *   skb->csum_level indicates the number of consecutive checksums found in
+ *   the packet minus one that have been verified as CHECKSUM_UNNECESSARY.
+ *   For instance if a device receives an IPv6->UDP->GRE->IPv4->TCP packet
+ *   and a device is able to verify the checksums for UDP (possibly zero),
+ *   GRE (checksum flag is set), and TCP-- skb->csum_level would be set to
+ *   two. If the device were only able to verify the UDP checksum and not
+ *   GRE, either because it doesn't support GRE checksum of because GRE
+ *   checksum is bad, skb->csum_level would be set to zero (TCP checksum is
+ *   not considered in this case).
  *
  * CHECKSUM_COMPLETE:
  *
 #define CHECKSUM_COMPLETE      2
 #define CHECKSUM_PARTIAL       3
 
+/* Maximum value in skb->csum_level */
+#define SKB_MAX_CSUM_LEVEL     3
+
 #define SKB_DATA_ALIGN(X)      ALIGN(X, SMP_CACHE_BYTES)
 #define SKB_WITH_OVERHEAD(X)   \
        ((X) - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
@@ -452,6 +473,7 @@ static inline u32 skb_mstamp_us_delta(const struct skb_mstamp *t1,
  *     @tc_verd: traffic control verdict
  *     @hash: the packet hash
  *     @queue_mapping: Queue mapping for multiqueue devices
+ *     @xmit_more: More SKBs are pending for this queue
  *     @ndisc_nodetype: router type (from link layer)
  *     @ooo_okay: allow the mapping of a socket to a queue to be changed
  *     @l4_hash: indicate hash is a canonical 4-tuple hash over transport
@@ -558,6 +580,7 @@ struct sk_buff {
 
        __u16                   queue_mapping;
        kmemcheck_bitfield_begin(flags2);
+       __u8                    xmit_more:1;
 #ifdef CONFIG_IPV6_NDISC_NODETYPE
        __u8                    ndisc_nodetype:2;
 #endif
@@ -569,16 +592,12 @@ struct sk_buff {
        __u8                    wifi_acked:1;
        __u8                    no_fcs:1;
        __u8                    head_frag:1;
-       /* Encapsulation protocol and NIC drivers should use
-        * this flag to indicate to each other if the skb contains
-        * encapsulated packet or not and maybe use the inner packet
-        * headers if needed
-        */
+       /* Indicates the inner headers are valid in the skbuff. */
        __u8                    encapsulation:1;
        __u8                    encap_hdr_csum:1;
        __u8                    csum_valid:1;
        __u8                    csum_complete_sw:1;
-       /* 2/4 bit hole (depending on ndisc_nodetype presence) */
+       /* 1/3 bit hole (depending on ndisc_nodetype presence) */
        kmemcheck_bitfield_end(flags2);
 
 #if defined CONFIG_NET_DMA || defined CONFIG_NET_RX_BUSY_POLL
@@ -596,6 +615,12 @@ struct sk_buff {
                __u32           reserved_tailroom;
        };
 
+       kmemcheck_bitfield_begin(flags3);
+       __u8                    csum_level:2;
+       __u8                    csum_bad:1;
+       /* 13 bit hole */
+       kmemcheck_bitfield_end(flags3);
+
        __be16                  inner_protocol;
        __u16                   inner_transport_header;
        __u16                   inner_network_header;
@@ -1860,18 +1885,6 @@ static inline int pskb_network_may_pull(struct sk_buff *skb, unsigned int len)
        return pskb_may_pull(skb, skb_network_offset(skb) + len);
 }
 
-static inline void skb_pop_rcv_encapsulation(struct sk_buff *skb)
-{
-       /* Only continue with checksum unnecessary if device indicated
-        * it is valid across encapsulation (skb->encapsulation was set).
-        */
-       if (skb->ip_summed == CHECKSUM_UNNECESSARY && !skb->encapsulation)
-               skb->ip_summed = CHECKSUM_NONE;
-
-       skb->encapsulation = 0;
-       skb->csum_valid = 0;
-}
-
 /*
  * CPUs often take a performance hit when accessing unaligned memory
  * locations. The actual performance hit varies, it can be small if the
@@ -2567,20 +2580,26 @@ __wsum __skb_checksum(const struct sk_buff *skb, int offset, int len,
 __wsum skb_checksum(const struct sk_buff *skb, int offset, int len,
                    __wsum csum);
 
-static inline void *skb_header_pointer(const struct sk_buff *skb, int offset,
-                                      int len, void *buffer)
+static inline void *__skb_header_pointer(const struct sk_buff *skb, int offset,
+                                        int len, void *data, int hlen, void *buffer)
 {
-       int hlen = skb_headlen(skb);
-
        if (hlen - offset >= len)
-               return skb->data + offset;
+               return data + offset;
 
-       if (skb_copy_bits(skb, offset, buffer, len) < 0)
+       if (!skb ||
+           skb_copy_bits(skb, offset, buffer, len) < 0)
                return NULL;
 
        return buffer;
 }
 
+static inline void *skb_header_pointer(const struct sk_buff *skb, int offset,
+                                      int len, void *buffer)
+{
+       return __skb_header_pointer(skb, offset, len, skb->data,
+                                   skb_headlen(skb), buffer);
+}
+
 /**
  *     skb_needs_linearize - check if we need to linearize a given skb
  *                           depending on the given device features.
@@ -2671,6 +2690,8 @@ static inline ktime_t net_invalid_timestamp(void)
        return ktime_set(0, 0);
 }
 
+struct sk_buff *skb_clone_sk(struct sk_buff *skb);
+
 #ifdef CONFIG_NETWORK_PHY_TIMESTAMPING
 
 void skb_clone_tx_timestamp(struct sk_buff *skb);
@@ -2786,6 +2807,42 @@ static inline __sum16 skb_checksum_complete(struct sk_buff *skb)
               0 : __skb_checksum_complete(skb);
 }
 
+static inline void __skb_decr_checksum_unnecessary(struct sk_buff *skb)
+{
+       if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
+               if (skb->csum_level == 0)
+                       skb->ip_summed = CHECKSUM_NONE;
+               else
+                       skb->csum_level--;
+       }
+}
+
+static inline void __skb_incr_checksum_unnecessary(struct sk_buff *skb)
+{
+       if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
+               if (skb->csum_level < SKB_MAX_CSUM_LEVEL)
+                       skb->csum_level++;
+       } else if (skb->ip_summed == CHECKSUM_NONE) {
+               skb->ip_summed = CHECKSUM_UNNECESSARY;
+               skb->csum_level = 0;
+       }
+}
+
+static inline void __skb_mark_checksum_bad(struct sk_buff *skb)
+{
+       /* Mark current checksum as bad (typically called from GRO
+        * path). In the case that ip_summed is CHECKSUM_NONE
+        * this must be the first checksum encountered in the packet.
+        * When ip_summed is CHECKSUM_UNNECESSARY, this is the first
+        * checksum after the last one validated. For UDP, a zero
+        * checksum can not be marked as bad.
+        */
+
+       if (skb->ip_summed == CHECKSUM_NONE ||
+           skb->ip_summed == CHECKSUM_UNNECESSARY)
+               skb->csum_bad = 1;
+}
+
 /* Check if we need to perform checksum complete validation.
  *
  * Returns true if checksum complete is needed, false otherwise
@@ -2797,6 +2854,7 @@ static inline bool __skb_checksum_validate_needed(struct sk_buff *skb,
 {
        if (skb_csum_unnecessary(skb) || (zero_okay && !check)) {
                skb->csum_valid = 1;
+               __skb_decr_checksum_unnecessary(skb);
                return false;
        }
 
@@ -2826,6 +2884,9 @@ static inline __sum16 __skb_checksum_validate_complete(struct sk_buff *skb,
                        skb->csum_valid = 1;
                        return 0;
                }
+       } else if (skb->csum_bad) {
+               /* ip_summed == CHECKSUM_NONE in this case */
+               return 1;
        }
 
        skb->csum = psum;
@@ -2883,6 +2944,26 @@ static inline __wsum null_compute_pseudo(struct sk_buff *skb, int proto)
 #define skb_checksum_simple_validate(skb)                              \
        __skb_checksum_validate(skb, 0, true, false, 0, null_compute_pseudo)
 
+static inline bool __skb_checksum_convert_check(struct sk_buff *skb)
+{
+       return (skb->ip_summed == CHECKSUM_NONE &&
+               skb->csum_valid && !skb->csum_bad);
+}
+
+static inline void __skb_checksum_convert(struct sk_buff *skb,
+                                         __sum16 check, __wsum pseudo)
+{
+       skb->csum = ~pseudo;
+       skb->ip_summed = CHECKSUM_COMPLETE;
+}
+
+#define skb_checksum_try_convert(skb, proto, check, compute_pseudo)    \
+do {                                                                   \
+       if (__skb_checksum_convert_check(skb))                          \
+               __skb_checksum_convert(skb, check,                      \
+                                      compute_pseudo(skb, proto));     \
+} while (0)
+
 #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
 void nf_conntrack_destroy(struct nf_conntrack *nfct);
 static inline void nf_conntrack_put(struct nf_conntrack *nfct)
@@ -3137,7 +3218,9 @@ bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off);
 
 int skb_checksum_setup(struct sk_buff *skb, bool recalculate);
 
-u32 __skb_get_poff(const struct sk_buff *skb);
+u32 skb_get_poff(const struct sk_buff *skb);
+u32 __skb_get_poff(const struct sk_buff *skb, void *data,
+                  const struct flow_keys *keys, int hlen);
 
 /**
  * skb_head_is_locked - Determine if the skb->head is locked down
index e713543336f12a972e3eaa200f9c73a42920ba97..46d188a9947c6401bfa91f7f32802c8d4707c025 100644 (file)
@@ -253,6 +253,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
  *     the device whose settings are being modified.
  * @transfer: adds a message to the controller's transfer queue.
  * @cleanup: frees controller-specific state
+ * @can_dma: determine whether this master supports DMA
  * @queued: whether this master is providing an internal message queue
  * @kworker: thread struct for message pump
  * @kworker_task: pointer to task for message pump kworker thread
@@ -262,6 +263,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
  * @cur_msg: the currently in-flight message
  * @cur_msg_prepared: spi_prepare_message was called for the currently
  *                    in-flight message
+ * @cur_msg_mapped: message has been mapped for DMA
  * @xfer_completion: used by core transfer_one_message()
  * @busy: message pump is busy
  * @running: message pump is running
@@ -299,6 +301,10 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
  * @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
  *     are not GPIOs (driven by the SPI controller itself).
+ * @dma_tx: DMA transmit channel
+ * @dma_rx: DMA receive channel
+ * @dummy_rx: dummy receive buffer for full-duplex devices
+ * @dummy_tx: dummy transmit buffer for full-duplex devices
  *
  * Each SPI master controller can communicate with one or more @spi_device
  * children.  These make a small bus, sharing MOSI, MISO and SCK signals
@@ -632,6 +638,7 @@ struct spi_transfer {
  *     addresses for each transfer buffer
  * @complete: called to report transaction completions
  * @context: the argument to complete() when it's called
+ * @frame_length: the total number of bytes in the message
  * @actual_length: the total number of bytes that were transferred in all
  *     successful segments
  * @status: zero for success, else negative errno
index fa5258f322e7998664a257e2d17f8397cd4346b2..e567f0dbf2828d24bff4ab38cf705c6e20034ebb 100644 (file)
@@ -276,7 +276,7 @@ struct tcp_sock {
        u32     retrans_stamp;  /* Timestamp of the last retransmit,
                                 * also used in SYN-SENT to remember stamp of
                                 * the first SYN. */
-       u32     undo_marker;    /* tracking retrans started here. */
+       u32     undo_marker;    /* snd_una upon a new recovery episode. */
        int     undo_retrans;   /* number of undoable retransmissions. */
        u32     total_retrans;  /* Total retransmits for entire connection */
 
index 059052306831496d88de2f143930a32593b8ac79..9a82c7dc3fdd9f1fd35d62fb2ab0734516c9ad6c 100644 (file)
@@ -183,13 +183,8 @@ static inline bool tick_nohz_full_cpu(int cpu)
 
 extern void tick_nohz_init(void);
 extern void __tick_nohz_full_check(void);
+extern void tick_nohz_full_kick(void);
 extern void tick_nohz_full_kick_cpu(int cpu);
-
-static inline void tick_nohz_full_kick(void)
-{
-       tick_nohz_full_kick_cpu(smp_processor_id());
-}
-
 extern void tick_nohz_full_kick_all(void);
 extern void __tick_nohz_task_switch(struct task_struct *tsk);
 #else
index 247cfdcc4b08bbf377ff5819ebd02683806b0c83..ee3277593222cf314f9b030eec6ec09d0c38c4e4 100644 (file)
@@ -49,7 +49,11 @@ struct udp_sock {
        unsigned int     corkflag;      /* Cork is required */
        __u8             encap_type;    /* Is this an Encapsulation socket? */
        unsigned char    no_check6_tx:1,/* Send zero UDP6 checksums on TX? */
-                        no_check6_rx:1;/* Allow zero UDP6 checksums on RX? */
+                        no_check6_rx:1,/* Allow zero UDP6 checksums on RX? */
+                        convert_csum:1;/* On receive, convert checksum
+                                        * unnecessary to checksum complete
+                                        * if possible.
+                                        */
        /*
         * Following member retains the information to create a UDP header
         * when the socket is uncorked.
@@ -98,6 +102,16 @@ static inline bool udp_get_no_check6_rx(struct sock *sk)
        return udp_sk(sk)->no_check6_rx;
 }
 
+static inline void udp_set_convert_csum(struct sock *sk, bool val)
+{
+       udp_sk(sk)->convert_csum = val;
+}
+
+static inline bool udp_get_convert_csum(struct sock *sk)
+{
+       return udp_sk(sk)->convert_csum;
+}
+
 #define udp_portaddr_for_each_entry(__sk, node, list) \
        hlist_nulls_for_each_entry(__sk, node, list, __sk_common.skc_portaddr_node)
 
index b5d5af3aa469961af36b30b0aea2da1d4e959bac..b0ded1333865309ecd9e771bf33ee872c3abd56e 100644 (file)
@@ -302,7 +302,7 @@ struct hci_dev {
        __u32                   req_status;
        __u32                   req_result;
 
-       struct crypto_blkcipher *tfm_aes;
+       void                    *smp_data;
 
        struct discovery_state  discovery;
        struct hci_conn_hash    conn_hash;
@@ -464,6 +464,8 @@ struct hci_conn_params {
                HCI_AUTO_CONN_ALWAYS,
                HCI_AUTO_CONN_LINK_LOSS,
        } auto_connect;
+
+       struct hci_conn *conn;
 };
 
 extern struct list_head hci_dev_list;
@@ -968,6 +970,9 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
 #define lmp_host_le_capable(dev)   (!!((dev)->features[1][0] & LMP_HOST_LE))
 #define lmp_host_le_br_capable(dev) (!!((dev)->features[1][0] & LMP_HOST_LE_BREDR))
 
+#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
+                               !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
+
 /* ----- HCI protocols ----- */
 #define HCI_PROTO_DEFER             0x01
 
@@ -1256,6 +1261,8 @@ bool hci_req_pending(struct hci_dev *hdev);
 void hci_req_add_le_scan_disable(struct hci_request *req);
 void hci_req_add_le_passive_scan(struct hci_request *req);
 
+void hci_update_page_scan(struct hci_dev *hdev, struct hci_request *req);
+
 struct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
                               const void *param, u32 timeout);
 struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen,
@@ -1351,6 +1358,7 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
 void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
                      u8 addr_type, s8 rssi, u8 *name, u8 name_len);
 void mgmt_discovering(struct hci_dev *hdev, u8 discovering);
+bool mgmt_powering_down(struct hci_dev *hdev);
 void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent);
 void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk);
 void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
index 8df15ad0d43fadc17f82aed2cb2b9115ff6a425f..cedda399f9c0e7fb98ca62a1612e65f35e9a68b4 100644 (file)
@@ -625,6 +625,9 @@ struct l2cap_conn {
 
        struct delayed_work     info_timer;
 
+       int                     disconn_err;
+       struct work_struct      disconn_work;
+
        struct sk_buff          *rx_skb;
        __u32                   rx_len;
        __u8                    tx_ident;
@@ -635,8 +638,7 @@ struct l2cap_conn {
 
        __u8                    disc_reason;
 
-       struct delayed_work     security_timer;
-       struct smp_chan         *smp_chan;
+       struct l2cap_chan       *smp;
 
        struct list_head        chan_l;
        struct mutex            chan_lock;
@@ -708,6 +710,7 @@ enum {
        FLAG_EFS_ENABLE,
        FLAG_DEFER_SETUP,
        FLAG_LE_CONN_REQ_SENT,
+       FLAG_PENDING_SECURITY,
 };
 
 enum {
@@ -837,18 +840,43 @@ static inline struct l2cap_chan *l2cap_chan_no_new_connection(struct l2cap_chan
        return NULL;
 }
 
+static inline int l2cap_chan_no_recv(struct l2cap_chan *chan, struct sk_buff *skb)
+{
+       return -ENOSYS;
+}
+
+static inline struct sk_buff *l2cap_chan_no_alloc_skb(struct l2cap_chan *chan,
+                                                     unsigned long hdr_len,
+                                                     unsigned long len, int nb)
+{
+       return ERR_PTR(-ENOSYS);
+}
+
 static inline void l2cap_chan_no_teardown(struct l2cap_chan *chan, int err)
 {
 }
 
+static inline void l2cap_chan_no_close(struct l2cap_chan *chan)
+{
+}
+
 static inline void l2cap_chan_no_ready(struct l2cap_chan *chan)
 {
 }
 
+static inline void l2cap_chan_no_state_change(struct l2cap_chan *chan,
+                                             int state, int err)
+{
+}
+
 static inline void l2cap_chan_no_defer(struct l2cap_chan *chan)
 {
 }
 
+static inline void l2cap_chan_no_suspend(struct l2cap_chan *chan)
+{
+}
+
 static inline void l2cap_chan_no_resume(struct l2cap_chan *chan)
 {
 }
@@ -918,6 +946,7 @@ void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan,
                       u8 status);
 void __l2cap_physical_cfm(struct l2cap_chan *chan, int result);
 
+void l2cap_conn_shutdown(struct l2cap_conn *conn, int err);
 void l2cap_conn_get(struct l2cap_conn *conn);
 void l2cap_conn_put(struct l2cap_conn *conn);
 
index 0a080c4de2754d0b9fc64ecf54e8dc4bcb477cf3..ab21299c8f4dfc13a50a9f23043b19df25f87a69 100644 (file)
@@ -1503,12 +1503,14 @@ enum cfg80211_signal_type {
  * @tsf: TSF contained in the frame that carried these IEs
  * @rcu_head: internal use, for freeing
  * @len: length of the IEs
+ * @from_beacon: these IEs are known to come from a beacon
  * @data: IE data
  */
 struct cfg80211_bss_ies {
        u64 tsf;
        struct rcu_head rcu_head;
        int len;
+       bool from_beacon;
        u8 data[];
 };
 
@@ -3765,11 +3767,25 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
 }
 
 /**
- * cfg80211_inform_bss - inform cfg80211 of a new BSS
+ * enum cfg80211_bss_frame_type - frame type that the BSS data came from
+ * @CFG80211_BSS_FTYPE_UNKNOWN: driver doesn't know whether the data is
+ *     from a beacon or probe response
+ * @CFG80211_BSS_FTYPE_BEACON: data comes from a beacon
+ * @CFG80211_BSS_FTYPE_PRESP: data comes from a probe response
+ */
+enum cfg80211_bss_frame_type {
+       CFG80211_BSS_FTYPE_UNKNOWN,
+       CFG80211_BSS_FTYPE_BEACON,
+       CFG80211_BSS_FTYPE_PRESP,
+};
+
+/**
+ * cfg80211_inform_bss_width - inform cfg80211 of a new BSS
  *
  * @wiphy: the wiphy reporting the BSS
  * @rx_channel: The channel the frame was received on
  * @scan_width: width of the control channel
+ * @ftype: frame type (if known)
  * @bssid: the BSSID of the BSS
  * @tsf: the TSF sent by the peer in the beacon/probe response (or 0)
  * @capability: the capability field sent by the peer
@@ -3789,6 +3805,7 @@ struct cfg80211_bss * __must_check
 cfg80211_inform_bss_width(struct wiphy *wiphy,
                          struct ieee80211_channel *rx_channel,
                          enum nl80211_bss_scan_width scan_width,
+                         enum cfg80211_bss_frame_type ftype,
                          const u8 *bssid, u64 tsf, u16 capability,
                          u16 beacon_interval, const u8 *ie, size_t ielen,
                          s32 signal, gfp_t gfp);
@@ -3796,12 +3813,13 @@ cfg80211_inform_bss_width(struct wiphy *wiphy,
 static inline struct cfg80211_bss * __must_check
 cfg80211_inform_bss(struct wiphy *wiphy,
                    struct ieee80211_channel *rx_channel,
+                   enum cfg80211_bss_frame_type ftype,
                    const u8 *bssid, u64 tsf, u16 capability,
                    u16 beacon_interval, const u8 *ie, size_t ielen,
                    s32 signal, gfp_t gfp)
 {
        return cfg80211_inform_bss_width(wiphy, rx_channel,
-                                        NL80211_BSS_CHAN_WIDTH_20,
+                                        NL80211_BSS_CHAN_WIDTH_20, ftype,
                                         bssid, tsf, capability,
                                         beacon_interval, ie, ielen, signal,
                                         gfp);
@@ -4412,7 +4430,6 @@ void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr,
  * @buf: Management frame (header + body)
  * @len: length of the frame data
  * @flags: flags, as defined in enum nl80211_rxmgmt_flags
- * @gfp: context flags
  *
  * This function is called whenever an Action frame is received for a station
  * mode interface, but is not processed in kernel.
@@ -4423,7 +4440,7 @@ void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr,
  * driver is responsible for rejecting the frame.
  */
 bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_dbm,
-                     const u8 *buf, size_t len, u32 flags, gfp_t gfp);
+                     const u8 *buf, size_t len, u32 flags);
 
 /**
  * cfg80211_mgmt_tx_status - notification of TX status for management frame
index fe0eab32ce76dd42845e8bc466c8bade5f429157..aeee28081245c9215f10badd611f58ba0124fcd0 100644 (file)
@@ -66,7 +66,7 @@ typedef s32 codel_tdiff_t;
 
 static inline codel_time_t codel_get_time(void)
 {
-       u64 ns = ktime_to_ns(ktime_get());
+       u64 ns = ktime_get_ns();
 
        return ns >> CODEL_SHIFT;
 }
index 6efce384451e56f16d8aab0847a6a7be4e94e0a0..97712927a9d2a5f50f09932ec54e7db01f25ef6b 100644 (file)
 #include <linux/list.h>
 #include <linux/timer.h>
 #include <linux/workqueue.h>
+#include <linux/of.h>
+#include <linux/phy.h>
+#include <linux/phy_fixed.h>
+
+/* Not an official ethertype value, used only internally for DSA
+ * demultiplexing
+ */
+#define ETH_P_BRCMTAG          (ETH_P_XDSA + 1)
 
 #define DSA_MAX_SWITCHES       4
 #define DSA_MAX_PORTS          12
@@ -26,6 +34,12 @@ struct dsa_chip_data {
        struct device   *mii_bus;
        int             sw_addr;
 
+       /* Device tree node pointer for this specific switch chip
+        * used during switch setup in case additional properties
+        * and resources needs to be used
+        */
+       struct device_node *of_node;
+
        /*
         * The names of the switch's ports.  Use "cpu" to
         * designate the switch port that the cpu is connected to,
@@ -34,6 +48,7 @@ struct dsa_chip_data {
         * or any other string to indicate this is a physical port.
         */
        char            *port_names[DSA_MAX_PORTS];
+       struct device_node *port_dn[DSA_MAX_PORTS];
 
        /*
         * An array (with nr_chips elements) of which element [a]
@@ -59,6 +74,8 @@ struct dsa_platform_data {
        struct dsa_chip_data    *chip;
 };
 
+struct dsa_device_ops;
+
 struct dsa_switch_tree {
        /*
         * Configuration data for the platform device that owns
@@ -71,6 +88,7 @@ struct dsa_switch_tree {
         * protocol to use.
         */
        struct net_device       *master_netdev;
+       const struct dsa_device_ops     *ops;
        __be16                  tag_protocol;
 
        /*
@@ -119,6 +137,7 @@ struct dsa_switch {
         */
        u32                     dsa_port_mask;
        u32                     phys_port_mask;
+       u32                     phys_mii_mask;
        struct mii_bus          *slave_mii_bus;
        struct net_device       *ports[DSA_MAX_PORTS];
 };
@@ -169,6 +188,14 @@ struct dsa_switch_driver {
         */
        void    (*poll_link)(struct dsa_switch *ds);
 
+       /*
+        * Link state adjustment (called from libphy)
+        */
+       void    (*adjust_link)(struct dsa_switch *ds, int port,
+                               struct phy_device *phydev);
+       void    (*fixed_link_update)(struct dsa_switch *ds, int port,
+                               struct fixed_phy_status *st);
+
        /*
         * ethtool hardware statistics.
         */
@@ -186,21 +213,9 @@ static inline void *ds_to_priv(struct dsa_switch *ds)
        return (void *)(ds + 1);
 }
 
-/*
- * The original DSA tag format and some other tag formats have no
- * ethertype, which means that we need to add a little hack to the
- * networking receive path to make sure that received frames get
- * the right ->protocol assigned to them when one of those tag
- * formats is in use.
- */
-static inline bool dsa_uses_dsa_tags(struct dsa_switch_tree *dst)
-{
-       return !!(dst->tag_protocol == htons(ETH_P_DSA));
-}
-
-static inline bool dsa_uses_trailer_tags(struct dsa_switch_tree *dst)
+static inline bool dsa_uses_tagged_protocol(struct dsa_switch_tree *dst)
 {
-       return !!(dst->tag_protocol == htons(ETH_P_TRAILER));
+       return dst->tag_protocol != 0;
 }
 
 #endif
index 6667a054763adfad3407d59d0f6810fb13f56a14..7ee2df083542365e9d317fa1dbc2bbcfbbe34aa6 100644 (file)
@@ -27,7 +27,19 @@ struct flow_keys {
        u8 ip_proto;
 };
 
-bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow);
-__be32 skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto);
+bool __skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow,
+                       void *data, __be16 proto, int nhoff, int hlen);
+static inline bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow)
+{
+       return __skb_flow_dissect(skb, flow, NULL, 0, 0, 0);
+}
+__be32 __skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto,
+                           void *data, int hlen_proto);
+static inline __be32 skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto)
+{
+       return __skb_flow_get_ports(skb, thoff, ip_proto, NULL, 0);
+}
 u32 flow_hash_from_keys(struct flow_keys *keys);
+unsigned int flow_get_hlen(const unsigned char *data, unsigned int max_len,
+                          __be16 protocol);
 #endif
index 01d590ee5e7eb5250eaef9e0880153c257b706bd..80479abddf73cc181899e1115a572727f578633d 100644 (file)
@@ -61,7 +61,6 @@ struct inet_peer {
 struct inet_peer_base {
        struct inet_peer __rcu  *root;
        seqlock_t               lock;
-       u32                     flush_seq;
        int                     total;
 };
 
index db4a771b9ef3a6893bb2ae5d5f8692bfec5c571d..14bfc8e1bcf9c374f836145151706182f0544ac7 100644 (file)
@@ -229,8 +229,6 @@ static inline int inet_is_local_reserved_port(struct net *net, int port)
 }
 #endif
 
-extern int sysctl_ip_nonlocal_bind;
-
 /* From inetpeer.c */
 extern int inet_peer_threshold;
 extern int inet_peer_minttl;
@@ -364,6 +362,14 @@ static inline void inet_set_txhash(struct sock *sk)
        sk->sk_txhash = flow_hash_from_keys(&keys);
 }
 
+static inline __wsum inet_gro_compute_pseudo(struct sk_buff *skb, int proto)
+{
+       const struct iphdr *iph = skb_gro_network_header(skb);
+
+       return csum_tcpudp_nofold(iph->saddr, iph->daddr,
+                                 skb_gro_len(skb), proto, 0);
+}
+
 /*
  *     Map a multicast IP onto multicast MAC for type ethernet.
  */
index 55236cb711745fc76ef4c897bcf70e957b34611c..1a49b73f7f6e372381f9d1f3b7cffdc5649794c6 100644 (file)
@@ -48,6 +48,14 @@ static inline __wsum ip6_compute_pseudo(struct sk_buff *skb, int proto)
                                            skb->len, proto, 0));
 }
 
+static inline __wsum ip6_gro_compute_pseudo(struct sk_buff *skb, int proto)
+{
+       const struct ipv6hdr *iph = skb_gro_network_header(skb);
+
+       return ~csum_unfold(csum_ipv6_magic(&iph->saddr, &iph->daddr,
+                                           skb_gro_len(skb), proto, 0));
+}
+
 static __inline__ __sum16 tcp_v6_check(int len,
                                   const struct in6_addr *saddr,
                                   const struct in6_addr *daddr,
index 9922093f575e20fa2e53a903a68da7773469c600..dc9d2a27c3158115b927b3f4b93e5bd98799d749 100644 (file)
@@ -65,7 +65,8 @@ struct fnhe_hash_bucket {
        struct fib_nh_exception __rcu   *chain;
 };
 
-#define FNHE_HASH_SIZE         2048
+#define FNHE_HASH_SHIFT                11
+#define FNHE_HASH_SIZE         (1 << FNHE_HASH_SHIFT)
 #define FNHE_RECLAIM_DEPTH     5
 
 struct fib_nh {
@@ -87,7 +88,7 @@ struct fib_nh {
        int                     nh_saddr_genid;
        struct rtable __rcu * __percpu *nh_pcpu_rth_output;
        struct rtable __rcu     *nh_rth_input;
-       struct fnhe_hash_bucket *nh_exceptions;
+       struct fnhe_hash_bucket __rcu *nh_exceptions;
 };
 
 /*
index a2db816e8461cff706f23c725cf69372ab8bfcaa..7e247e9b87654bb99cabc2288d14ade201b3f965 100644 (file)
@@ -121,6 +121,7 @@ struct frag_hdr {
 
 /* sysctls */
 extern int sysctl_mld_max_msf;
+extern int sysctl_mld_qrv;
 
 #define _DEVINC(net, statname, modifier, idev, field)                  \
 ({                                                                     \
index dae2e24616e16bf3051af3dd31414f91f4220af9..c9b2bec8db47bc5fa661772f6891fe7e4a21f960 100644 (file)
@@ -1226,7 +1226,8 @@ struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev);
  *
  * @IEEE80211_KEY_FLAG_GENERATE_IV: This flag should be set by the
  *     driver to indicate that it requires IV generation for this
- *     particular key.
+ *     particular key. Setting this flag does not necessarily mean that SKBs
+ *     will have sufficient tailroom for ICV or MIC.
  * @IEEE80211_KEY_FLAG_GENERATE_MMIC: This flag should be set by
  *     the driver for a TKIP key if it requires Michael MIC
  *     generation in software.
@@ -1238,7 +1239,9 @@ struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev);
  * @IEEE80211_KEY_FLAG_PUT_IV_SPACE: This flag should be set by the driver
  *     if space should be prepared for the IV, but the IV
  *     itself should not be generated. Do not set together with
- *     @IEEE80211_KEY_FLAG_GENERATE_IV on the same key.
+ *     @IEEE80211_KEY_FLAG_GENERATE_IV on the same key. Setting this flag does
+ *     not necessarily mean that SKBs will have sufficient tailroom for ICV or
+ *     MIC.
  * @IEEE80211_KEY_FLAG_RX_MGMT: This key will be used to decrypt received
  *     management frames. The flag can help drivers that have a hardware
  *     crypto implementation that doesn't deal with management frames
@@ -1405,7 +1408,7 @@ struct ieee80211_sta_rates {
  * @supp_rates: Bitmap of supported rates (per band)
  * @ht_cap: HT capabilities of this STA; restricted to our own capabilities
  * @vht_cap: VHT capabilities of this STA; restricted to our own capabilities
- * @wme: indicates whether the STA supports WME. Only valid during AP-mode.
+ * @wme: indicates whether the STA supports QoS/WME.
  * @drv_priv: data area for driver use, will always be aligned to
  *     sizeof(void *), size is determined in hw information.
  * @uapsd_queues: bitmap of queues configured for uapsd. Only valid
@@ -1606,6 +1609,9 @@ struct ieee80211_tx_control {
  *     is not enabled the default action is to disconnect when getting the
  *     CSA frame.
  *
+ * @IEEE80211_HW_SUPPORTS_CLONED_SKBS: The driver will never modify the payload
+ *     or tailroom of TX skbs without copying them first.
+ *
  * @IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS: The HW supports scanning on all bands
  *     in one command, mac80211 doesn't have to run separate scans per band.
  */
@@ -1639,7 +1645,7 @@ enum ieee80211_hw_flags {
        IEEE80211_HW_TIMING_BEACON_ONLY                 = 1<<26,
        IEEE80211_HW_SUPPORTS_HT_CCK_RATES              = 1<<27,
        IEEE80211_HW_CHANCTX_STA_CSA                    = 1<<28,
-       /* bit 29 unused */
+       IEEE80211_HW_SUPPORTS_CLONED_SKBS               = 1<<29,
        IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS           = 1<<30,
 };
 
index e2070960bac009223c1c6caa1324d6323a478a7d..8170f8d7052b21f5b8e82d8cb7c1c52a56042378 100644 (file)
@@ -16,7 +16,6 @@ struct netns_sysctl_lowpan {
 struct netns_ieee802154_lowpan {
        struct netns_sysctl_lowpan sysctl;
        struct netns_frags      frags;
-       int                     max_dsize;
 };
 
 #endif
index aec5e12f9f19f1a6c506e47f60cc3056d7ce2a3d..24945cefc4fde6bfaf9c4560080c91b2e3b12d0d 100644 (file)
@@ -76,6 +76,7 @@ struct netns_ipv4 {
        int sysctl_tcp_ecn;
        int sysctl_ip_no_pmtu_disc;
        int sysctl_ip_fwd_use_pmtu;
+       int sysctl_ip_nonlocal_bind;
 
        int sysctl_fwmark_reflect;
        int sysctl_tcp_fwmark_accept;
index ec030cd7661693d3812035d350e242f9b271edc4..8bbe626e9ece3d927047fa59b8717301c65c6130 100644 (file)
@@ -50,7 +50,7 @@ typedef long  psched_tdiff_t;
 
 static inline psched_time_t psched_get_time(void)
 {
-       return PSCHED_NS2TICKS(ktime_to_ns(ktime_get()));
+       return PSCHED_NS2TICKS(ktime_get_ns());
 }
 
 static inline psched_tdiff_t
index 259992444e80ae0b88eaec4ff345d23fd8f81c75..dad7ab20a8cb204f08b2ecda724d5c1db5138ec8 100644 (file)
@@ -167,7 +167,7 @@ struct ieee80211_reg_rule {
 struct ieee80211_regdomain {
        struct rcu_head rcu_head;
        u32 n_reg_rules;
-       char alpha2[2];
+       char alpha2[3];
        enum nl80211_dfs_regions dfs_region;
        struct ieee80211_reg_rule reg_rules[];
 };
index f6e7397e799dbd9dd1007c8f4e494c4b3405d28e..9fbd856e67139f9525b2951b147ed6f9223f7540 100644 (file)
@@ -320,6 +320,19 @@ static inline sctp_assoc_t sctp_assoc2id(const struct sctp_association *asoc)
        return asoc ? asoc->assoc_id : 0;
 }
 
+static inline enum sctp_sstat_state
+sctp_assoc_to_state(const struct sctp_association *asoc)
+{
+       /* SCTP's uapi always had SCTP_EMPTY(=0) as a dummy state, but we
+        * got rid of it in kernel space. Therefore SCTP_CLOSED et al
+        * start at =1 in user space, but actually as =0 in kernel space.
+        * Now that we can not break user space and SCTP_EMPTY is exposed
+        * there, we need to fix it up with an ugly offset not to break
+        * applications. :(
+        */
+       return asoc->state + 1;
+}
+
 /* Look up the association by its id.  */
 struct sctp_association *sctp_id2assoc(struct sock *sk, sctp_assoc_t id);
 
index 7f2ab72f321a4bd437800ab551a5aff3a9eab44a..515a4d01e93240e68f25007f25ef5ff47953a2a9 100644 (file)
@@ -1574,7 +1574,12 @@ struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force,
 void sock_wfree(struct sk_buff *skb);
 void skb_orphan_partial(struct sk_buff *skb);
 void sock_rfree(struct sk_buff *skb);
+void sock_efree(struct sk_buff *skb);
+#ifdef CONFIG_INET
 void sock_edemux(struct sk_buff *skb);
+#else
+#define sock_edemux(skb) sock_efree(skb)
+#endif
 
 int sock_setsockopt(struct socket *sock, int level, int op,
                    char __user *optval, unsigned int optlen);
@@ -2041,6 +2046,7 @@ void sk_stop_timer(struct sock *sk, struct timer_list *timer);
 int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb);
 
 int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb);
+struct sk_buff *sock_dequeue_err_skb(struct sock *sk);
 
 /*
  *     Recover an error report and clear atomically
@@ -2165,9 +2171,7 @@ sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb)
         */
        if (sock_flag(sk, SOCK_RCVTSTAMP) ||
            (sk->sk_tsflags & SOF_TIMESTAMPING_RX_SOFTWARE) ||
-           (kt.tv64 &&
-            (sk->sk_tsflags & SOF_TIMESTAMPING_SOFTWARE ||
-             skb_shinfo(skb)->tx_flags & SKBTX_ANY_SW_TSTAMP)) ||
+           (kt.tv64 && sk->sk_tsflags & SOF_TIMESTAMPING_SOFTWARE) ||
            (hwtstamps->hwtstamp.tv64 &&
             (sk->sk_tsflags & SOF_TIMESTAMPING_RAW_HARDWARE)))
                __sock_recv_timestamp(msg, sk, skb);
@@ -2195,6 +2199,8 @@ static inline void sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk,
                sk->sk_stamp = skb->tstamp;
 }
 
+void __sock_tx_timestamp(const struct sock *sk, __u8 *tx_flags);
+
 /**
  * sock_tx_timestamp - checks whether the outgoing packet is to be time stamped
  * @sk:                socket sending this packet
@@ -2202,7 +2208,13 @@ static inline void sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk,
  *
  * Note : callers should take care of initial *tx_flags value (usually 0)
  */
-void sock_tx_timestamp(const struct sock *sk, __u8 *tx_flags);
+static inline void sock_tx_timestamp(const struct sock *sk, __u8 *tx_flags)
+{
+       if (unlikely(sk->sk_tsflags))
+               __sock_tx_timestamp(sk, tx_flags);
+       if (unlikely(sock_flag(sk, SOCK_WIFI_STATUS)))
+               *tx_flags |= SKBTX_WIFI_STATUS;
+}
 
 /**
  * sk_eat_skb - Release a skb if it is no longer needed
index 590e01a476acc913464322e8e54a1858d78b3bf7..a4201ef216e83849678f700e89fd35e143c96368 100644 (file)
@@ -672,6 +672,12 @@ void tcp_send_window_probe(struct sock *sk);
  */
 #define tcp_time_stamp         ((__u32)(jiffies))
 
+static inline u32 tcp_skb_timestamp(const struct sk_buff *skb)
+{
+       return skb->skb_mstamp.stamp_jiffies;
+}
+
+
 #define tcp_flag_byte(th) (((u_int8_t *)th)[13])
 
 #define TCPHDR_FIN 0x01
@@ -698,7 +704,7 @@ struct tcp_skb_cb {
        } header;       /* For incoming frames          */
        __u32           seq;            /* Starting sequence number     */
        __u32           end_seq;        /* SEQ + FIN + SYN + datalen    */
-       __u32           when;           /* used to compute rtt's        */
+       __u32           tcp_tw_isn;     /* isn chosen by tcp_timewait_state_process() */
        __u8            tcp_flags;      /* TCP header flags. (tcp[13])  */
 
        __u8            sacked;         /* State flags for SACK/FACK.   */
index 70f941368ace488dc93f4e78f81b1dca935cd87f..16f4e80f0519c6dc0b180a9aec58c9231eda506e 100644 (file)
@@ -158,6 +158,24 @@ static inline __sum16 udp_v4_check(int len, __be32 saddr,
 void udp_set_csum(bool nocheck, struct sk_buff *skb,
                  __be32 saddr, __be32 daddr, int len);
 
+struct sk_buff **udp_gro_receive(struct sk_buff **head, struct sk_buff *skb,
+                                struct udphdr *uh);
+int udp_gro_complete(struct sk_buff *skb, int nhoff);
+
+static inline struct udphdr *udp_gro_udphdr(struct sk_buff *skb)
+{
+       struct udphdr *uh;
+       unsigned int hlen, off;
+
+       off  = skb_gro_offset(skb);
+       hlen = off + sizeof(*uh);
+       uh   = skb_gro_header_fast(skb, off);
+       if (skb_gro_header_hard(skb, hlen))
+               uh = skb_gro_header_slow(skb, hlen, off);
+
+       return uh;
+}
+
 /* hash routines shared between UDPv4/6 and UDP-Litev4/6 */
 static inline void udp_lib_hash(struct sock *sk)
 {
index e52ef5357e088b568e958de0d8545953ab90cef5..c52b68577cb0edc0d00732cc67441a4ac30595be 100644 (file)
@@ -290,7 +290,7 @@ struct wimax_dev;
  *     This operation has to be synchronous, and return only when the
  *     reset is complete. In case of having had to resort to bus/cold
  *     reset implying a device disconnection, the call is allowed to
- *     return inmediately.
+ *     return immediately.
  *     NOTE: wimax_dev->mutex is NOT locked when this op is being
  *     called; however, wimax_dev->mutex_reset IS locked to ensure
  *     serialization of calls to wimax_reset().
diff --git a/include/rxrpc/types.h b/include/rxrpc/types.h
deleted file mode 100644 (file)
index 30d48f6..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/* types.h: Rx types
- *
- * Copyright (C) 2002 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 License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef _LINUX_RXRPC_TYPES_H
-#define _LINUX_RXRPC_TYPES_H
-
-#include <linux/types.h>
-#include <linux/list.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/spinlock.h>
-#include <linux/atomic.h>
-
-typedef uint32_t       rxrpc_seq_t;    /* Rx message sequence number */
-typedef uint32_t       rxrpc_serial_t; /* Rx message serial number */
-typedef __be32 rxrpc_seq_net_t; /* on-the-wire Rx message sequence number */
-typedef __be32 rxrpc_serial_net_t; /* on-the-wire Rx message serial number */
-
-struct rxrpc_call;
-struct rxrpc_connection;
-struct rxrpc_header;
-struct rxrpc_message;
-struct rxrpc_operation;
-struct rxrpc_peer;
-struct rxrpc_service;
-typedef struct rxrpc_timer rxrpc_timer_t;
-struct rxrpc_transport;
-
-typedef void (*rxrpc_call_attn_func_t)(struct rxrpc_call *call);
-typedef void (*rxrpc_call_error_func_t)(struct rxrpc_call *call);
-typedef void (*rxrpc_call_aemap_func_t)(struct rxrpc_call *call);
-
-#endif /* _LINUX_RXRPC_TYPES_H */
index fd0421c6d40a1dbce334ba1e3c423cee4a744434..95ed9424a11af26d21ba83865386d9e1e573231c 100644 (file)
@@ -527,6 +527,7 @@ enum iscsi_err {
        ISCSI_ERR_XMIT_FAILED           = ISCSI_ERR_BASE + 19,
        ISCSI_ERR_TCP_CONN_CLOSE        = ISCSI_ERR_BASE + 20,
        ISCSI_ERR_SCSI_EH_SESSION_RST   = ISCSI_ERR_BASE + 21,
+       ISCSI_ERR_NOP_TIMEDOUT          = ISCSI_ERR_BASE + 22,
 };
 
 /*
index be6ecae247b0c608df5aa2554079d6bc4efca482..c83a334dd00fa9186404917183115fca3124670c 100644 (file)
        .access = SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE | \
                  SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \
        .tlv.c = (snd_soc_bytes_tlv_callback), \
-       .info = snd_soc_info_bytes_ext, \
+       .info = snd_soc_bytes_info_ext, \
        .private_value = (unsigned long)&(struct soc_bytes_ext) \
                {.max = xcount, .get = xhandler_get, .put = xhandler_put, } }
 #define SOC_SINGLE_XR_SX(xname, xregbase, xregcount, xnbits, \
index 1c09820df58564f8d0430d996998edc6f8d893c0..3608bebd3d9c5e58a0349c6240a8670bd3d8bbfb 100644 (file)
@@ -107,7 +107,7 @@ DECLARE_EVENT_CLASS(softirq,
  * @vec_nr:  softirq vector number
  *
  * When used in combination with the softirq_exit tracepoint
- * we can determine the softirq handler runtine.
+ * we can determine the softirq handler routine.
  */
 DEFINE_EVENT(softirq, softirq_entry,
 
@@ -121,7 +121,7 @@ DEFINE_EVENT(softirq, softirq_entry,
  * @vec_nr:  softirq vector number
  *
  * When used in combination with the softirq_entry tracepoint
- * we can determine the softirq handler runtine.
+ * we can determine the softirq handler routine.
  */
 DEFINE_EVENT(softirq, softirq_exit,
 
index f1afd607f043cc6aa0a9da0649b1dc92eeaad275..11d11bc5c78f2d480ecac331cbf5d73f58001bb7 100644 (file)
@@ -703,9 +703,11 @@ __SYSCALL(__NR_renameat2, sys_renameat2)
 __SYSCALL(__NR_seccomp, sys_seccomp)
 #define __NR_getrandom 278
 __SYSCALL(__NR_getrandom, sys_getrandom)
+#define __NR_memfd_create 279
+__SYSCALL(__NR_memfd_create, sys_memfd_create)
 
 #undef __NR_syscalls
-#define __NR_syscalls 279
+#define __NR_syscalls 280
 
 /*
  * All syscalls below here should go away really,
index 509b2d7a41b7ea88e676409a39d483e5a450f029..fea6099608ef2244d2020fbf5dcfac3c7d886d91 100644 (file)
@@ -944,6 +944,7 @@ struct drm_radeon_cs_chunk {
 };
 
 /* drm_radeon_cs_reloc.flags */
+#define RADEON_RELOC_PRIO_MASK         (0xf << 0)
 
 struct drm_radeon_cs_reloc {
        uint32_t                handle;
index 24e9033f8b3f9f10fde3467b9122d59c9621edcd..fb3f7b675229d4abd5f4ba3d62e8ec03b4471f6f 100644 (file)
@@ -67,6 +67,7 @@ header-y += bfs_fs.h
 header-y += binfmts.h
 header-y += blkpg.h
 header-y += blktrace_api.h
+header-y += bpf.h
 header-y += bpqether.h
 header-y += bsg.h
 header-y += btrfs.h
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
new file mode 100644 (file)
index 0000000..479ed0b
--- /dev/null
@@ -0,0 +1,65 @@
+/* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ */
+#ifndef _UAPI__LINUX_BPF_H__
+#define _UAPI__LINUX_BPF_H__
+
+#include <linux/types.h>
+
+/* 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 */
+
+/* Register numbers */
+enum {
+       BPF_REG_0 = 0,
+       BPF_REG_1,
+       BPF_REG_2,
+       BPF_REG_3,
+       BPF_REG_4,
+       BPF_REG_5,
+       BPF_REG_6,
+       BPF_REG_7,
+       BPF_REG_8,
+       BPF_REG_9,
+       BPF_REG_10,
+       __MAX_BPF_REG,
+};
+
+/* BPF has 10 general purpose 64-bit registers and stack frame. */
+#define MAX_BPF_REG    __MAX_BPF_REG
+
+struct bpf_insn {
+       __u8    code;           /* opcode */
+       __u8    dst_reg:4;      /* dest register */
+       __u8    src_reg:4;      /* source register */
+       __s16   off;            /* signed offset */
+       __s32   imm;            /* signed immediate constant */
+};
+
+#endif /* _UAPI__LINUX_BPF_H__ */
index e3c7a719c76b4a586c40da9506adaa095857ede4..7a364f2f3d3faf71a6febe653eed26d24bb79708 100644 (file)
@@ -209,6 +209,32 @@ struct ethtool_value {
        __u32   data;
 };
 
+enum tunable_id {
+       ETHTOOL_ID_UNSPEC,
+       ETHTOOL_RX_COPYBREAK,
+};
+
+enum tunable_type_id {
+       ETHTOOL_TUNABLE_UNSPEC,
+       ETHTOOL_TUNABLE_U8,
+       ETHTOOL_TUNABLE_U16,
+       ETHTOOL_TUNABLE_U32,
+       ETHTOOL_TUNABLE_U64,
+       ETHTOOL_TUNABLE_STRING,
+       ETHTOOL_TUNABLE_S8,
+       ETHTOOL_TUNABLE_S16,
+       ETHTOOL_TUNABLE_S32,
+       ETHTOOL_TUNABLE_S64,
+};
+
+struct ethtool_tunable {
+       __u32   cmd;
+       __u32   id;
+       __u32   type_id;
+       __u32   len;
+       void    *data[0];
+};
+
 /**
  * struct ethtool_regs - hardware register dump
  * @cmd: Command number = %ETHTOOL_GREGS
@@ -1152,6 +1178,8 @@ enum ethtool_sfeatures_retval_bits {
 
 #define ETHTOOL_GRSSH          0x00000046 /* Get RX flow hash configuration */
 #define ETHTOOL_SRSSH          0x00000047 /* Set RX flow hash configuration */
+#define ETHTOOL_GTUNABLE       0x00000048 /* Get tunable configuration */
+#define ETHTOOL_STUNABLE       0x00000049 /* Set tunable configuration */
 
 /* compatibility with older code */
 #define SPARC_ETH_GSET         ETHTOOL_GSET
index 0f8210b8e0bc47ac0b7faab45a12ca6dcfbdf72d..aa63ed023c2b96b61b42231f9dd9b34b6ae46b66 100644 (file)
 #define ETH_P_PHONET   0x00F5          /* Nokia Phonet frames          */
 #define ETH_P_IEEE802154 0x00F6                /* IEEE802.15.4 frame           */
 #define ETH_P_CAIF     0x00F7          /* ST-Ericsson CAIF protocol    */
+#define ETH_P_XDSA     0x00F8          /* Multiplexed DSA protocol     */
 
 /*
  *     This is an Ethernet frame header.
index ff957604a7213136d72bf6ec0b34989e7637ccc4..c80f95f6ee786d5a66d5b65547384bea9f76c989 100644 (file)
@@ -215,6 +215,18 @@ enum in6_addr_gen_mode {
        IN6_ADDR_GEN_MODE_NONE,
 };
 
+/* Bridge section */
+
+enum {
+       IFLA_BR_UNSPEC,
+       IFLA_BR_FORWARD_DELAY,
+       IFLA_BR_HELLO_TIME,
+       IFLA_BR_MAX_AGE,
+       __IFLA_BR_MAX,
+};
+
+#define IFLA_BR_MAX    (__IFLA_BR_MAX - 1)
+
 enum {
        BRIDGE_MODE_UNSPEC,
        BRIDGE_MODE_HAIRPIN,
index f1db15b9c041ccad0f13a4206e73245b59e7c236..d097568da6908c8c9053aa64ef9fafafa2b11308 100644 (file)
@@ -3055,14 +3055,20 @@ enum nl80211_bss_scan_width {
  * @NL80211_BSS_BSSID: BSSID of the BSS (6 octets)
  * @NL80211_BSS_FREQUENCY: frequency in MHz (u32)
  * @NL80211_BSS_TSF: TSF of the received probe response/beacon (u64)
+ *     (if @NL80211_BSS_PRESP_DATA is present then this is known to be
+ *     from a probe response, otherwise it may be from the same beacon
+ *     that the NL80211_BSS_BEACON_TSF will be from)
  * @NL80211_BSS_BEACON_INTERVAL: beacon interval of the (I)BSS (u16)
  * @NL80211_BSS_CAPABILITY: capability field (CPU order, u16)
  * @NL80211_BSS_INFORMATION_ELEMENTS: binary attribute containing the
  *     raw information elements from the probe response/beacon (bin);
- *     if the %NL80211_BSS_BEACON_IES attribute is present, the IEs here are
- *     from a Probe Response frame; otherwise they are from a Beacon frame.
+ *     if the %NL80211_BSS_BEACON_IES attribute is present and the data is
+ *     different then the IEs here are from a Probe Response frame; otherwise
+ *     they are from a Beacon frame.
  *     However, if the driver does not indicate the source of the IEs, these
  *     IEs may be from either frame subtype.
+ *     If present, the @NL80211_BSS_PRESP_DATA attribute indicates that the
+ *     data here is known to be from a probe response, without any heuristics.
  * @NL80211_BSS_SIGNAL_MBM: signal strength of probe response/beacon
  *     in mBm (100 * dBm) (s32)
  * @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon
@@ -3074,6 +3080,10 @@ enum nl80211_bss_scan_width {
  *     yet been received
  * @NL80211_BSS_CHAN_WIDTH: channel width of the control channel
  *     (u32, enum nl80211_bss_scan_width)
+ * @NL80211_BSS_BEACON_TSF: TSF of the last received beacon (u64)
+ *     (not present if no beacon frame has been received yet)
+ * @NL80211_BSS_PRESP_DATA: the data in @NL80211_BSS_INFORMATION_ELEMENTS and
+ *     @NL80211_BSS_TSF is known to be from a probe response (flag attribute)
  * @__NL80211_BSS_AFTER_LAST: internal
  * @NL80211_BSS_MAX: highest BSS attribute
  */
@@ -3091,6 +3101,8 @@ enum nl80211_bss {
        NL80211_BSS_SEEN_MS_AGO,
        NL80211_BSS_BEACON_IES,
        NL80211_BSS_CHAN_WIDTH,
+       NL80211_BSS_BEACON_TSF,
+       NL80211_BSS_PRESP_DATA,
 
        /* keep last */
        __NL80211_BSS_AFTER_LAST,
diff --git a/include/uapi/linux/usbip.h b/include/uapi/linux/usbip.h
new file mode 100644 (file)
index 0000000..fa5db30
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ *     usbip.h
+ *
+ *     USBIP uapi defines and function prototypes etc.
+*/
+
+#ifndef _UAPI_LINUX_USBIP_H
+#define _UAPI_LINUX_USBIP_H
+
+/* usbip device status - exported in usbip device sysfs status */
+enum usbip_device_status {
+       /* sdev is available. */
+       SDEV_ST_AVAILABLE = 0x01,
+       /* sdev is now used. */
+       SDEV_ST_USED,
+       /* sdev is unusable because of a fatal error. */
+       SDEV_ST_ERROR,
+
+       /* vdev does not connect a remote device. */
+       VDEV_ST_NULL,
+       /* vdev is used, but the USB address is not assigned yet */
+       VDEV_ST_NOTASSIGNED,
+       VDEV_ST_USED,
+       VDEV_ST_ERROR
+};
+#endif /* _UAPI_LINUX_USBIP_H */
index c38355c1f3c9109b7d989dd1ae56ed4d06c51238..1590c49cae572f66a7172c9985b2e4d5e493a8db 100644 (file)
@@ -13,7 +13,7 @@
 #ifndef _UAPI_LINUX_XATTR_H
 #define _UAPI_LINUX_XATTR_H
 
-#ifdef __UAPI_DEF_XATTR
+#if __UAPI_DEF_XATTR
 #define __USE_KERNEL_XATTR_DEFS
 
 #define XATTR_CREATE   0x1     /* set value, fail if attr already exists */
index 7f0dbcbb34af1559657adea42b7c726f145a3986..8ee520f0ec708952f2a8928ff7a697da3e3d7ea2 100644 (file)
  * Andi Kleen - Fix a few bad bugs and races.
  * Kris Katterjohn - Added many additional checks in bpf_check_classic()
  */
+
 #include <linux/filter.h>
 #include <linux/skbuff.h>
+#include <linux/vmalloc.h>
+#include <linux/random.h>
+#include <linux/moduleloader.h>
 #include <asm/unaligned.h>
 
 /* Registers */
@@ -63,6 +67,103 @@ void *bpf_internal_load_pointer_neg_helper(const struct sk_buff *skb, int k, uns
        return NULL;
 }
 
+struct bpf_prog *bpf_prog_alloc(unsigned int size, gfp_t gfp_extra_flags)
+{
+       gfp_t gfp_flags = GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO |
+                         gfp_extra_flags;
+       struct bpf_work_struct *ws;
+       struct bpf_prog *fp;
+
+       size = round_up(size, PAGE_SIZE);
+       fp = __vmalloc(size, gfp_flags, PAGE_KERNEL);
+       if (fp == NULL)
+               return NULL;
+
+       ws = kmalloc(sizeof(*ws), GFP_KERNEL | gfp_extra_flags);
+       if (ws == NULL) {
+               vfree(fp);
+               return NULL;
+       }
+
+       fp->pages = size / PAGE_SIZE;
+       fp->work = ws;
+
+       return fp;
+}
+EXPORT_SYMBOL_GPL(bpf_prog_alloc);
+
+struct bpf_prog *bpf_prog_realloc(struct bpf_prog *fp_old, unsigned int size,
+                                 gfp_t gfp_extra_flags)
+{
+       gfp_t gfp_flags = GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO |
+                         gfp_extra_flags;
+       struct bpf_prog *fp;
+
+       BUG_ON(fp_old == NULL);
+
+       size = round_up(size, PAGE_SIZE);
+       if (size <= fp_old->pages * PAGE_SIZE)
+               return fp_old;
+
+       fp = __vmalloc(size, gfp_flags, PAGE_KERNEL);
+       if (fp != NULL) {
+               memcpy(fp, fp_old, fp_old->pages * PAGE_SIZE);
+               fp->pages = size / PAGE_SIZE;
+
+               /* We keep fp->work from fp_old around in the new
+                * reallocated structure.
+                */
+               fp_old->work = NULL;
+               __bpf_prog_free(fp_old);
+       }
+
+       return fp;
+}
+EXPORT_SYMBOL_GPL(bpf_prog_realloc);
+
+void __bpf_prog_free(struct bpf_prog *fp)
+{
+       kfree(fp->work);
+       vfree(fp);
+}
+EXPORT_SYMBOL_GPL(__bpf_prog_free);
+
+struct bpf_binary_header *
+bpf_jit_binary_alloc(unsigned int proglen, u8 **image_ptr,
+                    unsigned int alignment,
+                    bpf_jit_fill_hole_t bpf_fill_ill_insns)
+{
+       struct bpf_binary_header *hdr;
+       unsigned int size, hole, start;
+
+       /* Most of BPF filters are really small, but if some of them
+        * fill a page, allow at least 128 extra bytes to insert a
+        * random section of illegal instructions.
+        */
+       size = round_up(proglen + sizeof(*hdr) + 128, PAGE_SIZE);
+       hdr = module_alloc(size);
+       if (hdr == NULL)
+               return NULL;
+
+       /* Fill space with illegal/arch-dep instructions. */
+       bpf_fill_ill_insns(hdr, size);
+
+       hdr->pages = size / PAGE_SIZE;
+       hole = min_t(unsigned int, size - (proglen + sizeof(*hdr)),
+                    PAGE_SIZE - sizeof(*hdr));
+       start = (prandom_u32() % hole) & ~(alignment - 1);
+
+       /* Leave a random number of instructions before BPF code. */
+       *image_ptr = &hdr->image[start];
+
+       return hdr;
+}
+
+void bpf_jit_binary_free(struct bpf_binary_header *hdr)
+{
+       module_free(NULL, hdr);
+}
+
 /* 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.
@@ -180,6 +281,7 @@ static unsigned int __bpf_prog_run(void *ctx, const struct bpf_insn *insn)
                [BPF_LD | BPF_IND | BPF_W] = &&LD_IND_W,
                [BPF_LD | BPF_IND | BPF_H] = &&LD_IND_H,
                [BPF_LD | BPF_IND | BPF_B] = &&LD_IND_B,
+               [BPF_LD | BPF_IMM | BPF_DW] = &&LD_IMM_DW,
        };
        void *ptr;
        int off;
@@ -239,6 +341,10 @@ select_insn:
        ALU64_MOV_K:
                DST = IMM;
                CONT;
+       LD_IMM_DW:
+               DST = (u64) (u32) insn[0].imm | ((u64) (u32) insn[1].imm) << 32;
+               insn++;
+               CONT;
        ALU64_ARSH_X:
                (*(s64 *) &DST) >>= SRC;
                CONT;
@@ -523,12 +629,26 @@ void bpf_prog_select_runtime(struct bpf_prog *fp)
 
        /* Probe if internal BPF can be JITed */
        bpf_int_jit_compile(fp);
+       /* Lock whole bpf_prog as read-only */
+       bpf_prog_lock_ro(fp);
 }
 EXPORT_SYMBOL_GPL(bpf_prog_select_runtime);
 
-/* free internal BPF program */
+static void bpf_prog_free_deferred(struct work_struct *work)
+{
+       struct bpf_work_struct *ws;
+
+       ws = container_of(work, struct bpf_work_struct, work);
+       bpf_jit_free(ws->prog);
+}
+
+/* Free internal BPF program */
 void bpf_prog_free(struct bpf_prog *fp)
 {
-       bpf_jit_free(fp);
+       struct bpf_work_struct *ws = fp->work;
+
+       INIT_WORK(&ws->work, bpf_prog_free_deferred);
+       ws->prog = fp;
+       schedule_work(&ws->work);
 }
 EXPORT_SYMBOL_GPL(bpf_prog_free);
index 7dc8788cfd52dd222856057840a8d0a45a19816e..940aced4ed00ca5c1de330c6609c78f6a7c5b3c2 100644 (file)
@@ -1035,6 +1035,11 @@ static void cgroup_get(struct cgroup *cgrp)
        css_get(&cgrp->self);
 }
 
+static bool cgroup_tryget(struct cgroup *cgrp)
+{
+       return css_tryget(&cgrp->self);
+}
+
 static void cgroup_put(struct cgroup *cgrp)
 {
        css_put(&cgrp->self);
@@ -1147,7 +1152,8 @@ static struct cgroup *cgroup_kn_lock_live(struct kernfs_node *kn)
         * protection against removal.  Ensure @cgrp stays accessible and
         * break the active_ref protection.
         */
-       cgroup_get(cgrp);
+       if (!cgroup_tryget(cgrp))
+               return NULL;
        kernfs_break_active_protection(kn);
 
        mutex_lock(&cgroup_mutex);
@@ -3271,8 +3277,17 @@ int cgroup_add_legacy_cftypes(struct cgroup_subsys *ss, struct cftype *cfts)
 {
        struct cftype *cft;
 
-       for (cft = cfts; cft && cft->name[0] != '\0'; cft++)
-               cft->flags |= __CFTYPE_NOT_ON_DFL;
+       /*
+        * If legacy_flies_on_dfl, we want to show the legacy files on the
+        * dfl hierarchy but iff the target subsystem hasn't been updated
+        * for the dfl hierarchy yet.
+        */
+       if (!cgroup_legacy_files_on_dfl ||
+           ss->dfl_cftypes != ss->legacy_cftypes) {
+               for (cft = cfts; cft && cft->name[0] != '\0'; cft++)
+                       cft->flags |= __CFTYPE_NOT_ON_DFL;
+       }
+
        return cgroup_add_cftypes(ss, cfts);
 }
 
@@ -4387,6 +4402,15 @@ static void css_release_work_fn(struct work_struct *work)
                /* cgroup release path */
                cgroup_idr_remove(&cgrp->root->cgroup_idr, cgrp->id);
                cgrp->id = -1;
+
+               /*
+                * There are two control paths which try to determine
+                * cgroup from dentry without going through kernfs -
+                * cgroupstats_build() and css_tryget_online_from_dir().
+                * Those are supported by RCU protecting clearing of
+                * cgrp->kn->priv backpointer.
+                */
+               RCU_INIT_POINTER(*(void __rcu __force **)&cgrp->kn->priv, NULL);
        }
 
        mutex_unlock(&cgroup_mutex);
@@ -4543,6 +4567,11 @@ static int cgroup_mkdir(struct kernfs_node *parent_kn, const char *name,
        struct cftype *base_files;
        int ssid, ret;
 
+       /* Do not accept '\n' to prevent making /proc/<pid>/cgroup unparsable.
+        */
+       if (strchr(name, '\n'))
+               return -EINVAL;
+
        parent = cgroup_kn_lock_live(parent_kn);
        if (!parent)
                return -ENODEV;
@@ -4820,16 +4849,6 @@ static int cgroup_rmdir(struct kernfs_node *kn)
 
        cgroup_kn_unlock(kn);
 
-       /*
-        * There are two control paths which try to determine cgroup from
-        * dentry without going through kernfs - cgroupstats_build() and
-        * css_tryget_online_from_dir().  Those are supported by RCU
-        * protecting clearing of cgrp->kn->priv backpointer, which should
-        * happen after all files under it have been removed.
-        */
-       if (!ret)
-               RCU_INIT_POINTER(*(void __rcu __force **)&kn->priv, NULL);
-
        cgroup_put(cgrp);
        return ret;
 }
@@ -5416,7 +5435,7 @@ struct cgroup_subsys_state *css_tryget_online_from_dir(struct dentry *dentry,
        /*
         * This path doesn't originate from kernfs and @kn could already
         * have been or be removed at any point.  @kn->priv is RCU
-        * protected for this access.  See cgroup_rmdir() for details.
+        * protected for this access.  See css_release_work_fn() for details.
         */
        cgrp = rcu_dereference(kn->priv);
        if (cgrp)
index 633394f442f8a3cf63bc30b160b5345589ea57b7..ebb3c369d03d594067bda50bdffedd32159026e3 100644 (file)
@@ -226,7 +226,7 @@ static long compat_nanosleep_restart(struct restart_block *restart)
        ret = hrtimer_nanosleep_restart(restart);
        set_fs(oldfs);
 
-       if (ret) {
+       if (ret == -ERESTART_RESTARTBLOCK) {
                rmtp = restart->nanosleep.compat_rmtp;
 
                if (rmtp && compat_put_timespec(&rmt, rmtp))
@@ -256,7 +256,26 @@ COMPAT_SYSCALL_DEFINE2(nanosleep, struct compat_timespec __user *, rqtp,
                                HRTIMER_MODE_REL, CLOCK_MONOTONIC);
        set_fs(oldfs);
 
-       if (ret) {
+       /*
+        * hrtimer_nanosleep() can only return 0 or
+        * -ERESTART_RESTARTBLOCK here because:
+        *
+        * - we call it with HRTIMER_MODE_REL and therefor exclude the
+        *   -ERESTARTNOHAND return path.
+        *
+        * - we supply the rmtp argument from the task stack (due to
+        *   the necessary compat conversion. So the update cannot
+        *   fail, which excludes the -EFAULT return path as well. If
+        *   it fails nevertheless we have a bigger problem and wont
+        *   reach this place anymore.
+        *
+        * - if the return value is 0, we do not have to update rmtp
+        *    because there is no remaining time.
+        *
+        * We check for -ERESTART_RESTARTBLOCK nevertheless if the
+        * core implementation decides to return random nonsense.
+        */
+       if (ret == -ERESTART_RESTARTBLOCK) {
                struct restart_block *restart
                        = &current_thread_info()->restart_block;
 
@@ -266,7 +285,6 @@ COMPAT_SYSCALL_DEFINE2(nanosleep, struct compat_timespec __user *, rqtp,
                if (rmtp && compat_put_timespec(&rmt, rmtp))
                        return -EFAULT;
        }
-
        return ret;
 }
 
index c766ee54c0b18bd27f87d4fcfb7f3caa24781343..b64e238b553b9430361127b223d2a003b70b1c99 100644 (file)
@@ -18,6 +18,7 @@ unsigned long saved_max_pfn;
  * it under CONFIG_CRASH_DUMP and not CONFIG_PROC_VMCORE.
  */
 unsigned long long elfcorehdr_addr = ELFCORE_ADDR_MAX;
+EXPORT_SYMBOL_GPL(elfcorehdr_addr);
 
 /*
  * stores the size of elf header of crash image
index 1cf24b3e42ece4f2de8854bd882f127165866af6..f9c1ed002dbc81997e6e062f358c57b6e459ce84 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/cgroup.h>
 #include <linux/module.h>
 #include <linux/mman.h>
+#include <linux/compat.h>
 
 #include "internal.h"
 
@@ -3717,6 +3718,26 @@ static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        return 0;
 }
 
+#ifdef CONFIG_COMPAT
+static long perf_compat_ioctl(struct file *file, unsigned int cmd,
+                               unsigned long arg)
+{
+       switch (_IOC_NR(cmd)) {
+       case _IOC_NR(PERF_EVENT_IOC_SET_FILTER):
+       case _IOC_NR(PERF_EVENT_IOC_ID):
+               /* Fix up pointer size (usually 4 -> 8 in 32-on-64-bit case */
+               if (_IOC_SIZE(cmd) == sizeof(compat_uptr_t)) {
+                       cmd &= ~IOCSIZE_MASK;
+                       cmd |= sizeof(void *) << IOCSIZE_SHIFT;
+               }
+               break;
+       }
+       return perf_ioctl(file, cmd, arg);
+}
+#else
+# define perf_compat_ioctl NULL
+#endif
+
 int perf_event_task_enable(void)
 {
        struct perf_event *event;
@@ -4222,7 +4243,7 @@ static const struct file_operations perf_fops = {
        .read                   = perf_read,
        .poll                   = perf_poll,
        .unlocked_ioctl         = perf_ioctl,
-       .compat_ioctl           = perf_ioctl,
+       .compat_ioctl           = perf_compat_ioctl,
        .mmap                   = perf_mmap,
        .fasync                 = perf_fasync,
 };
index a2b28a2fd7b16d270c45b3c40719a35d0034c58d..6223fab9a9d22b7bedd5e6b1f23ccd8a0347d6d1 100644 (file)
@@ -517,6 +517,7 @@ out:
                chip->irq_eoi(&desc->irq_data);
        raw_spin_unlock(&desc->lock);
 }
+EXPORT_SYMBOL_GPL(handle_fasteoi_irq);
 
 /**
  *     handle_edge_irq - edge type IRQ handler
index 0b49a0a5810200da0925350e3d55dd1fc70b8638..2bee072268d94da0b7e19e60ee5ee90267ea2b63 100644 (file)
@@ -64,7 +64,9 @@ bool kexec_in_progress = false;
 char __weak kexec_purgatory[0];
 size_t __weak kexec_purgatory_size = 0;
 
+#ifdef CONFIG_KEXEC_FILE
 static int kexec_calculate_store_digests(struct kimage *image);
+#endif
 
 /* Location of the reserved area for the crash kernel */
 struct resource crashk_res = {
@@ -341,6 +343,7 @@ out_free_image:
        return ret;
 }
 
+#ifdef CONFIG_KEXEC_FILE
 static int copy_file_from_fd(int fd, void **buf, unsigned long *buf_len)
 {
        struct fd f = fdget(fd);
@@ -612,6 +615,9 @@ out_free_image:
        kfree(image);
        return ret;
 }
+#else /* CONFIG_KEXEC_FILE */
+static inline void kimage_file_post_load_cleanup(struct kimage *image) { }
+#endif /* CONFIG_KEXEC_FILE */
 
 static int kimage_is_destination_range(struct kimage *image,
                                        unsigned long start,
@@ -1375,6 +1381,7 @@ COMPAT_SYSCALL_DEFINE4(kexec_load, compat_ulong_t, entry,
 }
 #endif
 
+#ifdef CONFIG_KEXEC_FILE
 SYSCALL_DEFINE5(kexec_file_load, int, kernel_fd, int, initrd_fd,
                unsigned long, cmdline_len, const char __user *, cmdline_ptr,
                unsigned long, flags)
@@ -1451,6 +1458,8 @@ out:
        return ret;
 }
 
+#endif /* CONFIG_KEXEC_FILE */
+
 void crash_kexec(struct pt_regs *regs)
 {
        /* Take the kexec_mutex here to prevent sys_kexec_load
@@ -2006,6 +2015,7 @@ static int __init crash_save_vmcoreinfo_init(void)
 
 subsys_initcall(crash_save_vmcoreinfo_init);
 
+#ifdef CONFIG_KEXEC_FILE
 static int __kexec_add_segment(struct kimage *image, char *buf,
                               unsigned long bufsz, unsigned long mem,
                               unsigned long memsz)
@@ -2682,6 +2692,7 @@ int kexec_purgatory_get_set_symbol(struct kimage *image, const char *name,
 
        return 0;
 }
+#endif /* CONFIG_KEXEC_FILE */
 
 /*
  * Move into place and start executing a preloaded standalone
index 734e9a7d280bd22a046566cc40b1edf159f250bf..3995f546d0f3f9c7bc845e7053f7a099088108a2 100644 (file)
@@ -1778,7 +1778,18 @@ static int pre_handler_kretprobe(struct kprobe *p, struct pt_regs *regs)
        unsigned long hash, flags = 0;
        struct kretprobe_instance *ri;
 
-       /*TODO: consider to only swap the RA after the last pre_handler fired */
+       /*
+        * To avoid deadlocks, prohibit return probing in NMI contexts,
+        * just skip the probe and increase the (inexact) 'nmissed'
+        * statistical counter, so that the user is informed that
+        * something happened:
+        */
+       if (unlikely(in_nmi())) {
+               rp->nmissed++;
+               return 0;
+       }
+
+       /* TODO: consider to only swap the RA after the last pre_handler fired */
        hash = hash_ptr(current, KPROBE_HASH_BITS);
        raw_spin_lock_irqsave(&rp->lock, flags);
        if (!hlist_empty(&rp->free_instances)) {
index 6f69463f006653bb7f572ef71aa1034de3d69e9f..03214bd288e9a90876aa5f1c92b8ebd596520e54 100644 (file)
@@ -3304,6 +3304,11 @@ static int load_module(struct load_info *info, const char __user *uargs,
        mutex_lock(&module_mutex);
        module_bug_cleanup(mod);
        mutex_unlock(&module_mutex);
+
+       /* we can't deallocate the module until we clear memory protection */
+       unset_module_init_ro_nx(mod);
+       unset_module_core_ro_nx(mod);
+
  ddebug_cleanup:
        dynamic_debug_remove(info->debug);
        synchronize_sched();
index 5d49dcac2537045a6e23b4e1941164e2f59a0402..2df883a9d3cb26bcf35e2d2e2294226793a2563b 100644 (file)
@@ -179,6 +179,7 @@ extern void swsusp_show_speed(struct timeval *, struct timeval *,
 
 #ifdef CONFIG_SUSPEND
 /* kernel/power/suspend.c */
+extern const char *pm_labels[];
 extern const char *pm_states[];
 
 extern int suspend_devices_and_enter(suspend_state_t state);
index 6dadb25cb0d8023f987c2c0961f1f81b7fedb0ce..18c62195660f6c6c458d74346ee7979ec4388db4 100644 (file)
@@ -31,7 +31,7 @@
 
 #include "power.h"
 
-static const char *pm_labels[] = { "mem", "standby", "freeze", };
+const char *pm_labels[] = { "mem", "standby", "freeze", NULL };
 const char *pm_states[PM_SUSPEND_MAX];
 
 static const struct platform_suspend_ops *suspend_ops;
index 2f524928b6aac0a1e1cd108aef54d23c88a291a9..bd91bc177c93a65ca757c70467cd6e235af6a67c 100644 (file)
@@ -129,20 +129,20 @@ static int __init has_wakealarm(struct device *dev, const void *data)
  * at startup time.  They're normally disabled, for faster boot and because
  * we can't know which states really work on this particular system.
  */
-static suspend_state_t test_state __initdata = PM_SUSPEND_ON;
+static const char *test_state_label __initdata;
 
 static char warn_bad_state[] __initdata =
        KERN_WARNING "PM: can't test '%s' suspend state\n";
 
 static int __init setup_test_suspend(char *value)
 {
-       suspend_state_t i;
+       int i;
 
        /* "=mem" ==> "mem" */
        value++;
-       for (i = PM_SUSPEND_MIN; i < PM_SUSPEND_MAX; i++)
-               if (!strcmp(pm_states[i], value)) {
-                       test_state = i;
+       for (i = 0; pm_labels[i]; i++)
+               if (!strcmp(pm_labels[i], value)) {
+                       test_state_label = pm_labels[i];
                        return 0;
                }
 
@@ -158,13 +158,21 @@ static int __init test_suspend(void)
 
        struct rtc_device       *rtc = NULL;
        struct device           *dev;
+       suspend_state_t test_state;
 
        /* PM is initialized by now; is that state testable? */
-       if (test_state == PM_SUSPEND_ON)
-               goto done;
-       if (!pm_states[test_state]) {
-               printk(warn_bad_state, pm_states[test_state]);
-               goto done;
+       if (!test_state_label)
+               return 0;
+
+       for (test_state = PM_SUSPEND_MIN; test_state < PM_SUSPEND_MAX; test_state++) {
+               const char *state_label = pm_states[test_state];
+
+               if (state_label && !strcmp(test_state_label, state_label))
+                       break;
+       }
+       if (test_state == PM_SUSPEND_MAX) {
+               printk(warn_bad_state, test_state_label);
+               return 0;
        }
 
        /* RTCs have initialized by now too ... can we use one? */
@@ -173,13 +181,12 @@ static int __init test_suspend(void)
                rtc = rtc_class_open(dev_name(dev));
        if (!rtc) {
                printk(warn_no_rtc);
-               goto done;
+               return 0;
        }
 
        /* go for it */
        test_wakealarm(rtc, test_state);
        rtc_class_close(rtc);
-done:
        return 0;
 }
 late_initcall(test_suspend);
index 71e64c718f75d3f4d419c31f4546cf3fab76a4f4..6a86eb7bac45e7b540f1ab9ead7d412cf6ef60fa 100644 (file)
@@ -358,7 +358,7 @@ struct rcu_data {
        struct rcu_head **nocb_gp_tail;
        long nocb_gp_count;
        long nocb_gp_count_lazy;
-       bool nocb_leader_wake;          /* Is the nocb leader thread awake? */
+       bool nocb_leader_sleep;         /* Is the nocb leader thread asleep? */
        struct rcu_data *nocb_next_follower;
                                        /* Next follower in wakeup chain. */
 
index 00dc411e9676f92db54e0bbb3489bea9b87e731a..a7997e272564916d8ec2232b32867add334b6c77 100644 (file)
@@ -2074,9 +2074,9 @@ static void wake_nocb_leader(struct rcu_data *rdp, bool force)
 
        if (!ACCESS_ONCE(rdp_leader->nocb_kthread))
                return;
-       if (!ACCESS_ONCE(rdp_leader->nocb_leader_wake) || force) {
+       if (ACCESS_ONCE(rdp_leader->nocb_leader_sleep) || force) {
                /* Prior xchg orders against prior callback enqueue. */
-               ACCESS_ONCE(rdp_leader->nocb_leader_wake) = true;
+               ACCESS_ONCE(rdp_leader->nocb_leader_sleep) = false;
                wake_up(&rdp_leader->nocb_wq);
        }
 }
@@ -2253,7 +2253,7 @@ wait_again:
        if (!rcu_nocb_poll) {
                trace_rcu_nocb_wake(my_rdp->rsp->name, my_rdp->cpu, "Sleep");
                wait_event_interruptible(my_rdp->nocb_wq,
-                                        ACCESS_ONCE(my_rdp->nocb_leader_wake));
+                               !ACCESS_ONCE(my_rdp->nocb_leader_sleep));
                /* Memory barrier handled by smp_mb() calls below and repoll. */
        } else if (firsttime) {
                firsttime = false; /* Don't drown trace log with "Poll"! */
@@ -2292,12 +2292,12 @@ wait_again:
                schedule_timeout_interruptible(1);
 
                /* Rescan in case we were a victim of memory ordering. */
-               my_rdp->nocb_leader_wake = false;
-               smp_mb();  /* Ensure _wake false before scan. */
+               my_rdp->nocb_leader_sleep = true;
+               smp_mb();  /* Ensure _sleep true before scan. */
                for (rdp = my_rdp; rdp; rdp = rdp->nocb_next_follower)
                        if (ACCESS_ONCE(rdp->nocb_head)) {
                                /* Found CB, so short-circuit next wait. */
-                               my_rdp->nocb_leader_wake = true;
+                               my_rdp->nocb_leader_sleep = false;
                                break;
                        }
                goto wait_again;
@@ -2307,17 +2307,17 @@ wait_again:
        rcu_nocb_wait_gp(my_rdp);
 
        /*
-        * We left ->nocb_leader_wake set to reduce cache thrashing.
-        * We clear it now, but recheck for new callbacks while
+        * We left ->nocb_leader_sleep unset to reduce cache thrashing.
+        * We set it now, but recheck for new callbacks while
         * traversing our follower list.
         */
-       my_rdp->nocb_leader_wake = false;
-       smp_mb(); /* Ensure _wake false before scan of ->nocb_head. */
+       my_rdp->nocb_leader_sleep = true;
+       smp_mb(); /* Ensure _sleep true before scan of ->nocb_head. */
 
        /* Each pass through the following loop wakes a follower, if needed. */
        for (rdp = my_rdp; rdp; rdp = rdp->nocb_next_follower) {
                if (ACCESS_ONCE(rdp->nocb_head))
-                       my_rdp->nocb_leader_wake = true; /* No need to wait. */
+                       my_rdp->nocb_leader_sleep = false;/* No need to sleep.*/
                if (!rdp->nocb_gp_head)
                        continue; /* No CBs, so no need to wake follower. */
 
index da14b8d092961bf5680bf06004f980ad1ec43859..60c5a3856ab7a5266fabd7eef844b9d1a636d0a8 100644 (file)
@@ -351,15 +351,12 @@ static int find_next_iomem_res(struct resource *res, char *name,
        end = res->end;
        BUG_ON(start >= end);
 
-       read_lock(&resource_lock);
-
-       if (first_level_children_only) {
-               p = iomem_resource.child;
+       if (first_level_children_only)
                sibling_only = true;
-       } else
-               p = &iomem_resource;
 
-       while ((p = next_resource(p, sibling_only))) {
+       read_lock(&resource_lock);
+
+       for (p = iomem_resource.child; p; p = next_resource(p, sibling_only)) {
                if (p->flags != res->flags)
                        continue;
                if (name && strcmp(p->name, name))
index 44eb005c6695010e79a5041b837914a12c69aa45..84922befea8414468eafe1330ffc372ec9bdb8da 100644 (file)
@@ -395,16 +395,15 @@ static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog)
        if (!filter)
                goto free_prog;
 
-       filter->prog = kzalloc(bpf_prog_size(new_len),
-                              GFP_KERNEL|__GFP_NOWARN);
+       filter->prog = bpf_prog_alloc(bpf_prog_size(new_len), __GFP_NOWARN);
        if (!filter->prog)
                goto free_filter;
 
        ret = bpf_convert_filter(fp, fprog->len, filter->prog->insnsi, &new_len);
        if (ret)
                goto free_filter_prog;
-       kfree(fp);
 
+       kfree(fp);
        atomic_set(&filter->usage, 1);
        filter->prog->len = new_len;
 
@@ -413,7 +412,7 @@ static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog)
        return filter;
 
 free_filter_prog:
-       kfree(filter->prog);
+       __bpf_prog_free(filter->prog);
 free_filter:
        kfree(filter);
 free_prog:
index 99aa6ee3908fbbff83923b2a8bb4c72b06e3f281..f654a8a298fad5cac36465bdcb23fddeb854f2ef 100644 (file)
@@ -224,6 +224,20 @@ static DEFINE_PER_CPU(struct irq_work, nohz_full_kick_work) = {
        .func = nohz_full_kick_work_func,
 };
 
+/*
+ * Kick this CPU if it's full dynticks in order to force it to
+ * re-evaluate its dependency on the tick and restart it if necessary.
+ * This kick, unlike tick_nohz_full_kick_cpu() and tick_nohz_full_kick_all(),
+ * is NMI safe.
+ */
+void tick_nohz_full_kick(void)
+{
+       if (!tick_nohz_full_cpu(smp_processor_id()))
+               return;
+
+       irq_work_queue(&__get_cpu_var(nohz_full_kick_work));
+}
+
 /*
  * Kick the CPU if it's full dynticks in order to force it to
  * re-evaluate its dependency on the tick and restart it if necessary.
index fb4a9c2cf8d98db2256a6268fb8bbfb37673b2fe..ec1791fae96575ffe49c9aa1a2f42cbc6b21df2a 100644 (file)
@@ -442,11 +442,12 @@ static void timekeeping_update(struct timekeeper *tk, unsigned int action)
                tk->ntp_error = 0;
                ntp_clear();
        }
-       update_vsyscall(tk);
-       update_pvclock_gtod(tk, action & TK_CLOCK_WAS_SET);
 
        tk_update_ktime_data(tk);
 
+       update_vsyscall(tk);
+       update_pvclock_gtod(tk, action & TK_CLOCK_WAS_SET);
+
        if (action & TK_MIRROR)
                memcpy(&shadow_timekeeper, &tk_core.timekeeper,
                       sizeof(tk_core.timekeeper));
index 1654b12c891a9367b2a8b20be93375990db6f22f..5916a8e59e878d4c6d9fc87bc370949f5501d962 100644 (file)
 #define FL_GLOBAL_CONTROL_MASK (FTRACE_OPS_FL_CONTROL)
 
 #ifdef CONFIG_DYNAMIC_FTRACE
-#define INIT_REGEX_LOCK(opsname)       \
-       .regex_lock     = __MUTEX_INITIALIZER(opsname.regex_lock),
+#define INIT_OPS_HASH(opsname) \
+       .func_hash              = &opsname.local_hash,                  \
+       .local_hash.regex_lock  = __MUTEX_INITIALIZER(opsname.local_hash.regex_lock),
+#define ASSIGN_OPS_HASH(opsname, val) \
+       .func_hash              = val, \
+       .local_hash.regex_lock  = __MUTEX_INITIALIZER(opsname.local_hash.regex_lock),
 #else
-#define INIT_REGEX_LOCK(opsname)
+#define INIT_OPS_HASH(opsname)
+#define ASSIGN_OPS_HASH(opsname, val)
 #endif
 
 static struct ftrace_ops ftrace_list_end __read_mostly = {
        .func           = ftrace_stub,
        .flags          = FTRACE_OPS_FL_RECURSION_SAFE | FTRACE_OPS_FL_STUB,
+       INIT_OPS_HASH(ftrace_list_end)
 };
 
 /* ftrace_enabled is a method to turn ftrace on or off */
@@ -140,7 +146,8 @@ static inline void ftrace_ops_init(struct ftrace_ops *ops)
 {
 #ifdef CONFIG_DYNAMIC_FTRACE
        if (!(ops->flags & FTRACE_OPS_FL_INITIALIZED)) {
-               mutex_init(&ops->regex_lock);
+               mutex_init(&ops->local_hash.regex_lock);
+               ops->func_hash = &ops->local_hash;
                ops->flags |= FTRACE_OPS_FL_INITIALIZED;
        }
 #endif
@@ -899,7 +906,7 @@ static void unregister_ftrace_profiler(void)
 static struct ftrace_ops ftrace_profile_ops __read_mostly = {
        .func           = function_profile_call,
        .flags          = FTRACE_OPS_FL_RECURSION_SAFE | FTRACE_OPS_FL_INITIALIZED,
-       INIT_REGEX_LOCK(ftrace_profile_ops)
+       INIT_OPS_HASH(ftrace_profile_ops)
 };
 
 static int register_ftrace_profiler(void)
@@ -1081,11 +1088,12 @@ static const struct ftrace_hash empty_hash = {
 #define EMPTY_HASH     ((struct ftrace_hash *)&empty_hash)
 
 static struct ftrace_ops global_ops = {
-       .func                   = ftrace_stub,
-       .notrace_hash           = EMPTY_HASH,
-       .filter_hash            = EMPTY_HASH,
-       .flags                  = FTRACE_OPS_FL_RECURSION_SAFE | FTRACE_OPS_FL_INITIALIZED,
-       INIT_REGEX_LOCK(global_ops)
+       .func                           = ftrace_stub,
+       .local_hash.notrace_hash        = EMPTY_HASH,
+       .local_hash.filter_hash         = EMPTY_HASH,
+       INIT_OPS_HASH(global_ops)
+       .flags                          = FTRACE_OPS_FL_RECURSION_SAFE |
+                                         FTRACE_OPS_FL_INITIALIZED,
 };
 
 struct ftrace_page {
@@ -1226,8 +1234,8 @@ static void free_ftrace_hash_rcu(struct ftrace_hash *hash)
 void ftrace_free_filter(struct ftrace_ops *ops)
 {
        ftrace_ops_init(ops);
-       free_ftrace_hash(ops->filter_hash);
-       free_ftrace_hash(ops->notrace_hash);
+       free_ftrace_hash(ops->func_hash->filter_hash);
+       free_ftrace_hash(ops->func_hash->notrace_hash);
 }
 
 static struct ftrace_hash *alloc_ftrace_hash(int size_bits)
@@ -1288,9 +1296,9 @@ alloc_and_copy_ftrace_hash(int size_bits, struct ftrace_hash *hash)
 }
 
 static void
-ftrace_hash_rec_disable(struct ftrace_ops *ops, int filter_hash);
+ftrace_hash_rec_disable_modify(struct ftrace_ops *ops, int filter_hash);
 static void
-ftrace_hash_rec_enable(struct ftrace_ops *ops, int filter_hash);
+ftrace_hash_rec_enable_modify(struct ftrace_ops *ops, int filter_hash);
 
 static int
 ftrace_hash_move(struct ftrace_ops *ops, int enable,
@@ -1342,13 +1350,13 @@ update:
         * Remove the current set, update the hash and add
         * them back.
         */
-       ftrace_hash_rec_disable(ops, enable);
+       ftrace_hash_rec_disable_modify(ops, enable);
 
        old_hash = *dst;
        rcu_assign_pointer(*dst, new_hash);
        free_ftrace_hash_rcu(old_hash);
 
-       ftrace_hash_rec_enable(ops, enable);
+       ftrace_hash_rec_enable_modify(ops, enable);
 
        return 0;
 }
@@ -1382,8 +1390,8 @@ ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip, void *regs)
                return 0;
 #endif
 
-       filter_hash = rcu_dereference_raw_notrace(ops->filter_hash);
-       notrace_hash = rcu_dereference_raw_notrace(ops->notrace_hash);
+       filter_hash = rcu_dereference_raw_notrace(ops->func_hash->filter_hash);
+       notrace_hash = rcu_dereference_raw_notrace(ops->func_hash->notrace_hash);
 
        if ((ftrace_hash_empty(filter_hash) ||
             ftrace_lookup_ip(filter_hash, ip)) &&
@@ -1503,25 +1511,38 @@ static bool test_rec_ops_needs_regs(struct dyn_ftrace *rec)
 static void ftrace_remove_tramp(struct ftrace_ops *ops,
                                struct dyn_ftrace *rec)
 {
-       struct ftrace_func_entry *entry;
-
-       entry = ftrace_lookup_ip(ops->tramp_hash, rec->ip);
-       if (!entry)
+       /* If TRAMP is not set, no ops should have a trampoline for this */
+       if (!(rec->flags & FTRACE_FL_TRAMP))
                return;
 
+       rec->flags &= ~FTRACE_FL_TRAMP;
+
+       if ((!ftrace_hash_empty(ops->func_hash->filter_hash) &&
+            !ftrace_lookup_ip(ops->func_hash->filter_hash, rec->ip)) ||
+           ftrace_lookup_ip(ops->func_hash->notrace_hash, rec->ip))
+               return;
        /*
         * The tramp_hash entry will be removed at time
         * of update.
         */
        ops->nr_trampolines--;
-       rec->flags &= ~FTRACE_FL_TRAMP;
 }
 
-static void ftrace_clear_tramps(struct dyn_ftrace *rec)
+static void ftrace_clear_tramps(struct dyn_ftrace *rec, struct ftrace_ops *ops)
 {
        struct ftrace_ops *op;
 
+       /* If TRAMP is not set, no ops should have a trampoline for this */
+       if (!(rec->flags & FTRACE_FL_TRAMP))
+               return;
+
        do_for_each_ftrace_op(op, ftrace_ops_list) {
+               /*
+                * This function is called to clear other tramps
+                * not the one that is being updated.
+                */
+               if (op == ops)
+                       continue;
                if (op->nr_trampolines)
                        ftrace_remove_tramp(op, rec);
        } while_for_each_ftrace_op(op);
@@ -1554,14 +1575,14 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops,
         *   gets inversed.
         */
        if (filter_hash) {
-               hash = ops->filter_hash;
-               other_hash = ops->notrace_hash;
+               hash = ops->func_hash->filter_hash;
+               other_hash = ops->func_hash->notrace_hash;
                if (ftrace_hash_empty(hash))
                        all = 1;
        } else {
                inc = !inc;
-               hash = ops->notrace_hash;
-               other_hash = ops->filter_hash;
+               hash = ops->func_hash->notrace_hash;
+               other_hash = ops->func_hash->filter_hash;
                /*
                 * If the notrace hash has no items,
                 * then there's nothing to do.
@@ -1622,13 +1643,10 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops,
                                /*
                                 * If we are adding another function callback
                                 * to this function, and the previous had a
-                                * trampoline used, then we need to go back to
-                                * the default trampoline.
+                                * custom trampoline in use, then we need to go
+                                * back to the default trampoline.
                                 */
-                               rec->flags &= ~FTRACE_FL_TRAMP;
-
-                               /* remove trampolines from any ops for this rec */
-                               ftrace_clear_tramps(rec);
+                               ftrace_clear_tramps(rec, ops);
                        }
 
                        /*
@@ -1682,6 +1700,41 @@ static void ftrace_hash_rec_enable(struct ftrace_ops *ops,
        __ftrace_hash_rec_update(ops, filter_hash, 1);
 }
 
+static void ftrace_hash_rec_update_modify(struct ftrace_ops *ops,
+                                         int filter_hash, int inc)
+{
+       struct ftrace_ops *op;
+
+       __ftrace_hash_rec_update(ops, filter_hash, inc);
+
+       if (ops->func_hash != &global_ops.local_hash)
+               return;
+
+       /*
+        * If the ops shares the global_ops hash, then we need to update
+        * all ops that are enabled and use this hash.
+        */
+       do_for_each_ftrace_op(op, ftrace_ops_list) {
+               /* Already done */
+               if (op == ops)
+                       continue;
+               if (op->func_hash == &global_ops.local_hash)
+                       __ftrace_hash_rec_update(op, filter_hash, inc);
+       } while_for_each_ftrace_op(op);
+}
+
+static void ftrace_hash_rec_disable_modify(struct ftrace_ops *ops,
+                                          int filter_hash)
+{
+       ftrace_hash_rec_update_modify(ops, filter_hash, 0);
+}
+
+static void ftrace_hash_rec_enable_modify(struct ftrace_ops *ops,
+                                         int filter_hash)
+{
+       ftrace_hash_rec_update_modify(ops, filter_hash, 1);
+}
+
 static void print_ip_ins(const char *fmt, unsigned char *p)
 {
        int i;
@@ -1896,8 +1949,8 @@ unsigned long ftrace_get_addr_new(struct dyn_ftrace *rec)
        if (rec->flags & FTRACE_FL_TRAMP) {
                ops = ftrace_find_tramp_ops_new(rec);
                if (FTRACE_WARN_ON(!ops || !ops->trampoline)) {
-                       pr_warning("Bad trampoline accounting at: %p (%pS)\n",
-                                   (void *)rec->ip, (void *)rec->ip);
+                       pr_warn("Bad trampoline accounting at: %p (%pS) (%lx)\n",
+                               (void *)rec->ip, (void *)rec->ip, rec->flags);
                        /* Ftrace is shutting down, return anything */
                        return (unsigned long)FTRACE_ADDR;
                }
@@ -1964,7 +2017,7 @@ __ftrace_replace_code(struct dyn_ftrace *rec, int enable)
                return ftrace_make_call(rec, ftrace_addr);
 
        case FTRACE_UPDATE_MAKE_NOP:
-               return ftrace_make_nop(NULL, rec, ftrace_addr);
+               return ftrace_make_nop(NULL, rec, ftrace_old_addr);
 
        case FTRACE_UPDATE_MODIFY_CALL:
                return ftrace_modify_call(rec, ftrace_old_addr, ftrace_addr);
@@ -2227,7 +2280,10 @@ static int ftrace_save_ops_tramp_hash(struct ftrace_ops *ops)
        } while_for_each_ftrace_rec();
 
        /* The number of recs in the hash must match nr_trampolines */
-       FTRACE_WARN_ON(ops->tramp_hash->count != ops->nr_trampolines);
+       if (FTRACE_WARN_ON(ops->tramp_hash->count != ops->nr_trampolines))
+               pr_warn("count=%ld trampolines=%d\n",
+                       ops->tramp_hash->count,
+                       ops->nr_trampolines);
 
        return 0;
 }
@@ -2436,8 +2492,8 @@ static inline int ops_traces_mod(struct ftrace_ops *ops)
         * Filter_hash being empty will default to trace module.
         * But notrace hash requires a test of individual module functions.
         */
-       return ftrace_hash_empty(ops->filter_hash) &&
-               ftrace_hash_empty(ops->notrace_hash);
+       return ftrace_hash_empty(ops->func_hash->filter_hash) &&
+               ftrace_hash_empty(ops->func_hash->notrace_hash);
 }
 
 /*
@@ -2459,12 +2515,12 @@ ops_references_rec(struct ftrace_ops *ops, struct dyn_ftrace *rec)
                return 0;
 
        /* The function must be in the filter */
-       if (!ftrace_hash_empty(ops->filter_hash) &&
-           !ftrace_lookup_ip(ops->filter_hash, rec->ip))
+       if (!ftrace_hash_empty(ops->func_hash->filter_hash) &&
+           !ftrace_lookup_ip(ops->func_hash->filter_hash, rec->ip))
                return 0;
 
        /* If in notrace hash, we ignore it too */
-       if (ftrace_lookup_ip(ops->notrace_hash, rec->ip))
+       if (ftrace_lookup_ip(ops->func_hash->notrace_hash, rec->ip))
                return 0;
 
        return 1;
@@ -2785,10 +2841,10 @@ t_next(struct seq_file *m, void *v, loff_t *pos)
        } else {
                rec = &iter->pg->records[iter->idx++];
                if (((iter->flags & FTRACE_ITER_FILTER) &&
-                    !(ftrace_lookup_ip(ops->filter_hash, rec->ip))) ||
+                    !(ftrace_lookup_ip(ops->func_hash->filter_hash, rec->ip))) ||
 
                    ((iter->flags & FTRACE_ITER_NOTRACE) &&
-                    !ftrace_lookup_ip(ops->notrace_hash, rec->ip)) ||
+                    !ftrace_lookup_ip(ops->func_hash->notrace_hash, rec->ip)) ||
 
                    ((iter->flags & FTRACE_ITER_ENABLED) &&
                     !(rec->flags & FTRACE_FL_ENABLED))) {
@@ -2837,9 +2893,9 @@ static void *t_start(struct seq_file *m, loff_t *pos)
         * functions are enabled.
         */
        if ((iter->flags & FTRACE_ITER_FILTER &&
-            ftrace_hash_empty(ops->filter_hash)) ||
+            ftrace_hash_empty(ops->func_hash->filter_hash)) ||
            (iter->flags & FTRACE_ITER_NOTRACE &&
-            ftrace_hash_empty(ops->notrace_hash))) {
+            ftrace_hash_empty(ops->func_hash->notrace_hash))) {
                if (*pos > 0)
                        return t_hash_start(m, pos);
                iter->flags |= FTRACE_ITER_PRINTALL;
@@ -3001,12 +3057,12 @@ ftrace_regex_open(struct ftrace_ops *ops, int flag,
        iter->ops = ops;
        iter->flags = flag;
 
-       mutex_lock(&ops->regex_lock);
+       mutex_lock(&ops->func_hash->regex_lock);
 
        if (flag & FTRACE_ITER_NOTRACE)
-               hash = ops->notrace_hash;
+               hash = ops->func_hash->notrace_hash;
        else
-               hash = ops->filter_hash;
+               hash = ops->func_hash->filter_hash;
 
        if (file->f_mode & FMODE_WRITE) {
                const int size_bits = FTRACE_HASH_DEFAULT_BITS;
@@ -3041,7 +3097,7 @@ ftrace_regex_open(struct ftrace_ops *ops, int flag,
                file->private_data = iter;
 
  out_unlock:
-       mutex_unlock(&ops->regex_lock);
+       mutex_unlock(&ops->func_hash->regex_lock);
 
        return ret;
 }
@@ -3279,7 +3335,7 @@ static struct ftrace_ops trace_probe_ops __read_mostly =
 {
        .func           = function_trace_probe_call,
        .flags          = FTRACE_OPS_FL_INITIALIZED,
-       INIT_REGEX_LOCK(trace_probe_ops)
+       INIT_OPS_HASH(trace_probe_ops)
 };
 
 static int ftrace_probe_registered;
@@ -3342,7 +3398,7 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
                              void *data)
 {
        struct ftrace_func_probe *entry;
-       struct ftrace_hash **orig_hash = &trace_probe_ops.filter_hash;
+       struct ftrace_hash **orig_hash = &trace_probe_ops.func_hash->filter_hash;
        struct ftrace_hash *hash;
        struct ftrace_page *pg;
        struct dyn_ftrace *rec;
@@ -3359,7 +3415,7 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
        if (WARN_ON(not))
                return -EINVAL;
 
-       mutex_lock(&trace_probe_ops.regex_lock);
+       mutex_lock(&trace_probe_ops.func_hash->regex_lock);
 
        hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, *orig_hash);
        if (!hash) {
@@ -3428,7 +3484,7 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
  out_unlock:
        mutex_unlock(&ftrace_lock);
  out:
-       mutex_unlock(&trace_probe_ops.regex_lock);
+       mutex_unlock(&trace_probe_ops.func_hash->regex_lock);
        free_ftrace_hash(hash);
 
        return count;
@@ -3446,7 +3502,7 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
        struct ftrace_func_entry *rec_entry;
        struct ftrace_func_probe *entry;
        struct ftrace_func_probe *p;
-       struct ftrace_hash **orig_hash = &trace_probe_ops.filter_hash;
+       struct ftrace_hash **orig_hash = &trace_probe_ops.func_hash->filter_hash;
        struct list_head free_list;
        struct ftrace_hash *hash;
        struct hlist_node *tmp;
@@ -3468,7 +3524,7 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
                        return;
        }
 
-       mutex_lock(&trace_probe_ops.regex_lock);
+       mutex_lock(&trace_probe_ops.func_hash->regex_lock);
 
        hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, *orig_hash);
        if (!hash)
@@ -3521,7 +3577,7 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
        mutex_unlock(&ftrace_lock);
                
  out_unlock:
-       mutex_unlock(&trace_probe_ops.regex_lock);
+       mutex_unlock(&trace_probe_ops.func_hash->regex_lock);
        free_ftrace_hash(hash);
 }
 
@@ -3717,12 +3773,12 @@ ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len,
        if (unlikely(ftrace_disabled))
                return -ENODEV;
 
-       mutex_lock(&ops->regex_lock);
+       mutex_lock(&ops->func_hash->regex_lock);
 
        if (enable)
-               orig_hash = &ops->filter_hash;
+               orig_hash = &ops->func_hash->filter_hash;
        else
-               orig_hash = &ops->notrace_hash;
+               orig_hash = &ops->func_hash->notrace_hash;
 
        if (reset)
                hash = alloc_ftrace_hash(FTRACE_HASH_DEFAULT_BITS);
@@ -3752,7 +3808,7 @@ ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len,
        mutex_unlock(&ftrace_lock);
 
  out_regex_unlock:
-       mutex_unlock(&ops->regex_lock);
+       mutex_unlock(&ops->func_hash->regex_lock);
 
        free_ftrace_hash(hash);
        return ret;
@@ -3975,15 +4031,15 @@ int ftrace_regex_release(struct inode *inode, struct file *file)
 
        trace_parser_put(parser);
 
-       mutex_lock(&iter->ops->regex_lock);
+       mutex_lock(&iter->ops->func_hash->regex_lock);
 
        if (file->f_mode & FMODE_WRITE) {
                filter_hash = !!(iter->flags & FTRACE_ITER_FILTER);
 
                if (filter_hash)
-                       orig_hash = &iter->ops->filter_hash;
+                       orig_hash = &iter->ops->func_hash->filter_hash;
                else
-                       orig_hash = &iter->ops->notrace_hash;
+                       orig_hash = &iter->ops->func_hash->notrace_hash;
 
                mutex_lock(&ftrace_lock);
                ret = ftrace_hash_move(iter->ops, filter_hash,
@@ -3994,7 +4050,7 @@ int ftrace_regex_release(struct inode *inode, struct file *file)
                mutex_unlock(&ftrace_lock);
        }
 
-       mutex_unlock(&iter->ops->regex_lock);
+       mutex_unlock(&iter->ops->func_hash->regex_lock);
        free_ftrace_hash(iter->hash);
        kfree(iter);
 
@@ -4611,7 +4667,6 @@ void __init ftrace_init(void)
 static struct ftrace_ops global_ops = {
        .func                   = ftrace_stub,
        .flags                  = FTRACE_OPS_FL_RECURSION_SAFE | FTRACE_OPS_FL_INITIALIZED,
-       INIT_REGEX_LOCK(global_ops)
 };
 
 static int __init ftrace_nodyn_init(void)
@@ -4713,7 +4768,7 @@ ftrace_ops_control_func(unsigned long ip, unsigned long parent_ip,
 static struct ftrace_ops control_ops = {
        .func   = ftrace_ops_control_func,
        .flags  = FTRACE_OPS_FL_RECURSION_SAFE | FTRACE_OPS_FL_INITIALIZED,
-       INIT_REGEX_LOCK(control_ops)
+       INIT_OPS_HASH(control_ops)
 };
 
 static inline void
@@ -5145,6 +5200,17 @@ ftrace_enable_sysctl(struct ctl_table *table, int write,
 
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 
+static struct ftrace_ops graph_ops = {
+       .func                   = ftrace_stub,
+       .flags                  = FTRACE_OPS_FL_RECURSION_SAFE |
+                                  FTRACE_OPS_FL_INITIALIZED |
+                                  FTRACE_OPS_FL_STUB,
+#ifdef FTRACE_GRAPH_TRAMP_ADDR
+       .trampoline             = FTRACE_GRAPH_TRAMP_ADDR,
+#endif
+       ASSIGN_OPS_HASH(graph_ops, &global_ops.local_hash)
+};
+
 static int ftrace_graph_active;
 
 int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace)
@@ -5307,12 +5373,28 @@ static int ftrace_graph_entry_test(struct ftrace_graph_ent *trace)
  */
 static void update_function_graph_func(void)
 {
-       if (ftrace_ops_list == &ftrace_list_end ||
-           (ftrace_ops_list == &global_ops &&
-            global_ops.next == &ftrace_list_end))
-               ftrace_graph_entry = __ftrace_graph_entry;
-       else
+       struct ftrace_ops *op;
+       bool do_test = false;
+
+       /*
+        * The graph and global ops share the same set of functions
+        * to test. If any other ops is on the list, then
+        * the graph tracing needs to test if its the function
+        * it should call.
+        */
+       do_for_each_ftrace_op(op, ftrace_ops_list) {
+               if (op != &global_ops && op != &graph_ops &&
+                   op != &ftrace_list_end) {
+                       do_test = true;
+                       /* in double loop, break out with goto */
+                       goto out;
+               }
+       } while_for_each_ftrace_op(op);
+ out:
+       if (do_test)
                ftrace_graph_entry = ftrace_graph_entry_test;
+       else
+               ftrace_graph_entry = __ftrace_graph_entry;
 }
 
 static struct notifier_block ftrace_suspend_notifier = {
@@ -5353,16 +5435,7 @@ int register_ftrace_graph(trace_func_graph_ret_t retfunc,
        ftrace_graph_entry = ftrace_graph_entry_test;
        update_function_graph_func();
 
-       /* Function graph doesn't use the .func field of global_ops */
-       global_ops.flags |= FTRACE_OPS_FL_STUB;
-
-#ifdef CONFIG_DYNAMIC_FTRACE
-       /* Optimize function graph calling (if implemented by arch) */
-       if (FTRACE_GRAPH_TRAMP_ADDR != 0)
-               global_ops.trampoline = FTRACE_GRAPH_TRAMP_ADDR;
-#endif
-
-       ret = ftrace_startup(&global_ops, FTRACE_START_FUNC_RET);
+       ret = ftrace_startup(&graph_ops, FTRACE_START_FUNC_RET);
 
 out:
        mutex_unlock(&ftrace_lock);
@@ -5380,12 +5453,7 @@ void unregister_ftrace_graph(void)
        ftrace_graph_return = (trace_func_graph_ret_t)ftrace_stub;
        ftrace_graph_entry = ftrace_graph_entry_stub;
        __ftrace_graph_entry = ftrace_graph_entry_stub;
-       ftrace_shutdown(&global_ops, FTRACE_STOP_FUNC_RET);
-       global_ops.flags &= ~FTRACE_OPS_FL_STUB;
-#ifdef CONFIG_DYNAMIC_FTRACE
-       if (FTRACE_GRAPH_TRAMP_ADDR != 0)
-               global_ops.trampoline = 0;
-#endif
+       ftrace_shutdown(&graph_ops, FTRACE_STOP_FUNC_RET);
        unregister_pm_notifier(&ftrace_suspend_notifier);
        unregister_trace_sched_switch(ftrace_graph_probe_sched_switch, NULL);
 
index afb04b9b818a473f8b38e0aa94ee12ad84c44d1a..b38fb2b9e23772d3f3360ef556cf0714d4a44803 100644 (file)
@@ -626,8 +626,22 @@ int ring_buffer_poll_wait(struct ring_buffer *buffer, int cpu,
                work = &cpu_buffer->irq_work;
        }
 
-       work->waiters_pending = true;
        poll_wait(filp, &work->waiters, poll_table);
+       work->waiters_pending = true;
+       /*
+        * There's a tight race between setting the waiters_pending and
+        * checking if the ring buffer is empty.  Once the waiters_pending bit
+        * is set, the next event will wake the task up, but we can get stuck
+        * if there's only a single event in.
+        *
+        * FIXME: Ideally, we need a memory barrier on the writer side as well,
+        * but adding a memory barrier to all events will cause too much of a
+        * performance hit in the fast path.  We only need a memory barrier when
+        * the buffer goes from empty to having content.  But as this race is
+        * extremely small, and it's not a problem if another event comes in, we
+        * will fix it later.
+        */
+       smp_mb();
 
        if ((cpu == RING_BUFFER_ALL_CPUS && !ring_buffer_empty(buffer)) ||
            (cpu != RING_BUFFER_ALL_CPUS && !ring_buffer_empty_cpu(buffer, cpu)))
index 07c28323f88fe99d08900d82e3eacec6ca88fb91..a28590083622705dd007bffd5d3a57f87f133fed 100644 (file)
@@ -892,6 +892,10 @@ config DEBUG_WW_MUTEX_SLOWPATH
         the full mutex checks enabled with (CONFIG_PROVE_LOCKING) this
         will test all possible w/w mutex interface abuse with the
         exception of simply not acquiring all the required locks.
+        Note that this feature can introduce significant overhead, so
+        it really should not be enabled in a production or distro kernel,
+        even a debug kernel.  If you are a driver writer, enable it.  If
+        you are a distro, do not.
 
 config DEBUG_LOCK_ALLOC
        bool "Lock debugging: detect incorrect freeing of live locks"
@@ -1032,8 +1036,13 @@ config TRACE_IRQFLAGS
          either tracing or lock debugging.
 
 config STACKTRACE
-       bool
+       bool "Stack backtrace support"
        depends on STACKTRACE_SUPPORT
+       help
+         This option causes the kernel to create a /proc/pid/stack for
+         every process, showing its current stack trace.
+         It is also used by various kernel debugging features that require
+         stack trace generation.
 
 config DEBUG_KOBJECT
        bool "kobject debugging"
index c0b1007011e188836616509deef5876c207d32d4..ae146f0734eb59adcd2148af99f5ed89d013bd93 100644 (file)
@@ -1735,7 +1735,7 @@ ascend_old_tree:
 gc_complete:
        edit->set[0].to = new_root;
        assoc_array_apply_edit(edit);
-       edit->array->nr_leaves_on_tree = nr_leaves_on_tree;
+       array->nr_leaves_on_tree = nr_leaves_on_tree;
        return 0;
 
 enomem:
index c9b6bf3afe0cbfd833f34304416ad21b5a7c94fc..0bee183fa18faaf3314ac37244469f111408cd26 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/jiffies.h>
 #include <linux/random.h>
 #include <linux/sched.h>
+#include <asm/unaligned.h>
 
 #ifdef CONFIG_RANDOM32_SELFTEST
 static void __init prandom_state_selftest(void);
@@ -96,27 +97,23 @@ EXPORT_SYMBOL(prandom_u32);
  *     This is used for pseudo-randomness with no outside seeding.
  *     For more random results, use prandom_bytes().
  */
-void prandom_bytes_state(struct rnd_state *state, void *buf, int bytes)
+void prandom_bytes_state(struct rnd_state *state, void *buf, size_t bytes)
 {
-       unsigned char *p = buf;
-       int i;
-
-       for (i = 0; i < round_down(bytes, sizeof(u32)); i += sizeof(u32)) {
-               u32 random = prandom_u32_state(state);
-               int j;
+       u8 *ptr = buf;
 
-               for (j = 0; j < sizeof(u32); j++) {
-                       p[i + j] = random;
-                       random >>= BITS_PER_BYTE;
-               }
+       while (bytes >= sizeof(u32)) {
+               put_unaligned(prandom_u32_state(state), (u32 *) ptr);
+               ptr += sizeof(u32);
+               bytes -= sizeof(u32);
        }
-       if (i < bytes) {
-               u32 random = prandom_u32_state(state);
 
-               for (; i < bytes; i++) {
-                       p[i] = random;
-                       random >>= BITS_PER_BYTE;
-               }
+       if (bytes > 0) {
+               u32 rem = prandom_u32_state(state);
+               do {
+                       *ptr++ = (u8) rem;
+                       bytes--;
+                       rem >>= BITS_PER_BYTE;
+               } while (bytes > 0);
        }
 }
 EXPORT_SYMBOL(prandom_bytes_state);
@@ -126,7 +123,7 @@ EXPORT_SYMBOL(prandom_bytes_state);
  *     @buf: where to copy the pseudo-random bytes to
  *     @bytes: the requested number of bytes
  */
-void prandom_bytes(void *buf, int bytes)
+void prandom_bytes(void *buf, size_t bytes)
 {
        struct rnd_state *state = &get_cpu_var(net_rand_state);
 
@@ -137,7 +134,7 @@ EXPORT_SYMBOL(prandom_bytes);
 
 static void prandom_warmup(struct rnd_state *state)
 {
-       /* Calling RNG ten times to satify recurrence condition */
+       /* Calling RNG ten times to satisfy recurrence condition */
        prandom_u32_state(state);
        prandom_u32_state(state);
        prandom_u32_state(state);
@@ -152,7 +149,7 @@ static void prandom_warmup(struct rnd_state *state)
 
 static u32 __extract_hwseed(void)
 {
-       u32 val = 0;
+       unsigned int val = 0;
 
        (void)(arch_get_random_seed_int(&val) ||
               arch_get_random_int(&val));
@@ -228,7 +225,7 @@ static void __prandom_timer(unsigned long dontcare)
        prandom_seed(entropy);
 
        /* reseed every ~60 seconds, in [40 .. 80) interval with slack */
-       expires = 40 + (prandom_u32() % 40);
+       expires = 40 + prandom_u32_max(40);
        seed_timer.expires = jiffies + msecs_to_jiffies(expires * MSEC_PER_SEC);
 
        add_timer(&seed_timer);
index a2c78810ebc1a64a95903645dec6d14eed6ba1b6..8dfec3f26d4c4729f7fb96247d17ba86a7bc90c2 100644 (file)
@@ -298,7 +298,7 @@ int rhashtable_shrink(struct rhashtable *ht, gfp_t flags)
 
        ASSERT_RHT_MUTEX(ht);
 
-       if (tbl->size <= HASH_MIN_SIZE)
+       if (ht->shift <= ht->p.min_shift)
                return 0;
 
        ntbl = bucket_table_alloc(tbl->size / 2, flags);
@@ -506,9 +506,10 @@ void *rhashtable_lookup_compare(const struct rhashtable *ht, u32 hash,
 }
 EXPORT_SYMBOL_GPL(rhashtable_lookup_compare);
 
-static size_t rounded_hashtable_size(unsigned int nelem)
+static size_t rounded_hashtable_size(struct rhashtable_params *params)
 {
-       return max(roundup_pow_of_two(nelem * 4 / 3), HASH_MIN_SIZE);
+       return max(roundup_pow_of_two(params->nelem_hint * 4 / 3),
+                  1UL << params->min_shift);
 }
 
 /**
@@ -566,8 +567,11 @@ int rhashtable_init(struct rhashtable *ht, struct rhashtable_params *params)
            (!params->key_len && !params->obj_hashfn))
                return -EINVAL;
 
+       params->min_shift = max_t(size_t, params->min_shift,
+                                 ilog2(HASH_MIN_SIZE));
+
        if (params->nelem_hint)
-               size = rounded_hashtable_size(params->nelem_hint);
+               size = rounded_hashtable_size(params);
 
        tbl = bucket_table_alloc(size, GFP_KERNEL);
        if (tbl == NULL)
index 89e0345733bd33db9bc9ab1f6184a1d376ec9c89..413890815d3e7f247ead0aacda4937194ee5fcd4 100644 (file)
@@ -1341,6 +1341,44 @@ static struct bpf_test tests[] = {
                { },
                { { 0, -1 } }
        },
+       {
+               "INT: shifts by register",
+               .u.insns_int = {
+                       BPF_MOV64_IMM(R0, -1234),
+                       BPF_MOV64_IMM(R1, 1),
+                       BPF_ALU32_REG(BPF_RSH, R0, R1),
+                       BPF_JMP_IMM(BPF_JEQ, R0, 0x7ffffd97, 1),
+                       BPF_EXIT_INSN(),
+                       BPF_MOV64_IMM(R2, 1),
+                       BPF_ALU64_REG(BPF_LSH, R0, R2),
+                       BPF_MOV32_IMM(R4, -1234),
+                       BPF_JMP_REG(BPF_JEQ, R0, R4, 1),
+                       BPF_EXIT_INSN(),
+                       BPF_ALU64_IMM(BPF_AND, R4, 63),
+                       BPF_ALU64_REG(BPF_LSH, R0, R4), /* R0 <= 46 */
+                       BPF_MOV64_IMM(R3, 47),
+                       BPF_ALU64_REG(BPF_ARSH, R0, R3),
+                       BPF_JMP_IMM(BPF_JEQ, R0, -617, 1),
+                       BPF_EXIT_INSN(),
+                       BPF_MOV64_IMM(R2, 1),
+                       BPF_ALU64_REG(BPF_LSH, R4, R2), /* R4 = 46 << 1 */
+                       BPF_JMP_IMM(BPF_JEQ, R4, 92, 1),
+                       BPF_EXIT_INSN(),
+                       BPF_MOV64_IMM(R4, 4),
+                       BPF_ALU64_REG(BPF_LSH, R4, R4), /* R4 = 4 << 4 */
+                       BPF_JMP_IMM(BPF_JEQ, R4, 64, 1),
+                       BPF_EXIT_INSN(),
+                       BPF_MOV64_IMM(R4, 5),
+                       BPF_ALU32_REG(BPF_LSH, R4, R4), /* R4 = 5 << 5 */
+                       BPF_JMP_IMM(BPF_JEQ, R4, 160, 1),
+                       BPF_EXIT_INSN(),
+                       BPF_MOV64_IMM(R0, -1),
+                       BPF_EXIT_INSN(),
+               },
+               INTERNAL,
+               { },
+               { { 0, -1 } }
+       },
        {
                "INT: DIV + ABS",
                .u.insns_int = {
@@ -1697,6 +1735,27 @@ static struct bpf_test tests[] = {
                { },
                { { 1, 0 } },
        },
+       {
+               "load 64-bit immediate",
+               .u.insns_int = {
+                       BPF_LD_IMM64(R1, 0x567800001234L),
+                       BPF_MOV64_REG(R2, R1),
+                       BPF_MOV64_REG(R3, R2),
+                       BPF_ALU64_IMM(BPF_RSH, R2, 32),
+                       BPF_ALU64_IMM(BPF_LSH, R3, 32),
+                       BPF_ALU64_IMM(BPF_RSH, R3, 32),
+                       BPF_ALU64_IMM(BPF_MOV, R0, 0),
+                       BPF_JMP_IMM(BPF_JEQ, R2, 0x5678, 1),
+                       BPF_EXIT_INSN(),
+                       BPF_JMP_IMM(BPF_JEQ, R3, 0x1234, 1),
+                       BPF_EXIT_INSN(),
+                       BPF_ALU64_IMM(BPF_MOV, R0, 1),
+                       BPF_EXIT_INSN(),
+               },
+               INTERNAL,
+               { },
+               { { 0, 1 } }
+       },
 };
 
 static struct net_device dev;
@@ -1798,7 +1857,7 @@ static struct bpf_prog *generate_filter(int which, int *err)
                break;
 
        case INTERNAL:
-               fp = kzalloc(bpf_prog_size(flen), GFP_KERNEL);
+               fp = bpf_prog_alloc(bpf_prog_size(flen), 0);
                if (fp == NULL) {
                        pr_cont("UNEXPECTED_FAIL no memory left\n");
                        *err = -ENOMEM;
index 9eebfadeeee17f1f3650162dd1e34a88157ef39e..a67c26e0f360211f21fdb6b19f0f54fc9d3fe726 100644 (file)
@@ -217,7 +217,7 @@ void hugetlb_cgroup_uncharge_page(int idx, unsigned long nr_pages,
 
        if (hugetlb_cgroup_disabled())
                return;
-       VM_BUG_ON(!spin_is_locked(&hugetlb_lock));
+       lockdep_assert_held(&hugetlb_lock);
        h_cg = hugetlb_cgroup_from_page(page);
        if (unlikely(!h_cg))
                return;
index 6d2f219a48b01d371c1eb763f611d29a346890d9..70fad0c0dafb60c8f64d919b607bfb22e568afba 100644 (file)
@@ -192,8 +192,7 @@ phys_addr_t __init_memblock memblock_find_in_range_node(phys_addr_t size,
                                        phys_addr_t align, phys_addr_t start,
                                        phys_addr_t end, int nid)
 {
-       int ret;
-       phys_addr_t kernel_end;
+       phys_addr_t kernel_end, ret;
 
        /* pump up @end */
        if (end == MEMBLOCK_ALLOC_ACCESSIBLE)
index ec4dcf1b9562b6299f215e754768da18a36b156e..085dc6d2f876374c07a518866ecb1d25a2e8c419 100644 (file)
@@ -2534,6 +2534,8 @@ static int try_charge(struct mem_cgroup *memcg, gfp_t gfp_mask,
        unsigned long long size;
        int ret = 0;
 
+       if (mem_cgroup_is_root(memcg))
+               goto done;
 retry:
        if (consume_stock(memcg, nr_pages))
                goto done;
@@ -2611,9 +2613,7 @@ nomem:
        if (!(gfp_mask & __GFP_NOFAIL))
                return -ENOMEM;
 bypass:
-       memcg = root_mem_cgroup;
-       ret = -EINTR;
-       goto retry;
+       return -EINTR;
 
 done_restock:
        if (batch > nr_pages)
@@ -2626,6 +2626,9 @@ static void cancel_charge(struct mem_cgroup *memcg, unsigned int nr_pages)
 {
        unsigned long bytes = nr_pages * PAGE_SIZE;
 
+       if (mem_cgroup_is_root(memcg))
+               return;
+
        res_counter_uncharge(&memcg->res, bytes);
        if (do_swap_account)
                res_counter_uncharge(&memcg->memsw, bytes);
@@ -2640,6 +2643,9 @@ static void __mem_cgroup_cancel_local_charge(struct mem_cgroup *memcg,
 {
        unsigned long bytes = nr_pages * PAGE_SIZE;
 
+       if (mem_cgroup_is_root(memcg))
+               return;
+
        res_counter_uncharge_until(&memcg->res, memcg->res.parent, bytes);
        if (do_swap_account)
                res_counter_uncharge_until(&memcg->memsw,
@@ -4093,6 +4099,46 @@ out:
        return retval;
 }
 
+static unsigned long mem_cgroup_recursive_stat(struct mem_cgroup *memcg,
+                                              enum mem_cgroup_stat_index idx)
+{
+       struct mem_cgroup *iter;
+       long val = 0;
+
+       /* Per-cpu values can be negative, use a signed accumulator */
+       for_each_mem_cgroup_tree(iter, memcg)
+               val += mem_cgroup_read_stat(iter, idx);
+
+       if (val < 0) /* race ? */
+               val = 0;
+       return val;
+}
+
+static inline u64 mem_cgroup_usage(struct mem_cgroup *memcg, bool swap)
+{
+       u64 val;
+
+       if (!mem_cgroup_is_root(memcg)) {
+               if (!swap)
+                       return res_counter_read_u64(&memcg->res, RES_USAGE);
+               else
+                       return res_counter_read_u64(&memcg->memsw, RES_USAGE);
+       }
+
+       /*
+        * Transparent hugepages are still accounted for in MEM_CGROUP_STAT_RSS
+        * as well as in MEM_CGROUP_STAT_RSS_HUGE.
+        */
+       val = mem_cgroup_recursive_stat(memcg, MEM_CGROUP_STAT_CACHE);
+       val += mem_cgroup_recursive_stat(memcg, MEM_CGROUP_STAT_RSS);
+
+       if (swap)
+               val += mem_cgroup_recursive_stat(memcg, MEM_CGROUP_STAT_SWAP);
+
+       return val << PAGE_SHIFT;
+}
+
+
 static u64 mem_cgroup_read_u64(struct cgroup_subsys_state *css,
                               struct cftype *cft)
 {
@@ -4102,8 +4148,12 @@ static u64 mem_cgroup_read_u64(struct cgroup_subsys_state *css,
 
        switch (type) {
        case _MEM:
+               if (name == RES_USAGE)
+                       return mem_cgroup_usage(memcg, false);
                return res_counter_read_u64(&memcg->res, name);
        case _MEMSWAP:
+               if (name == RES_USAGE)
+                       return mem_cgroup_usage(memcg, true);
                return res_counter_read_u64(&memcg->memsw, name);
        case _KMEM:
                return res_counter_read_u64(&memcg->kmem, name);
@@ -4572,10 +4622,7 @@ static void __mem_cgroup_threshold(struct mem_cgroup *memcg, bool swap)
        if (!t)
                goto unlock;
 
-       if (!swap)
-               usage = res_counter_read_u64(&memcg->res, RES_USAGE);
-       else
-               usage = res_counter_read_u64(&memcg->memsw, RES_USAGE);
+       usage = mem_cgroup_usage(memcg, swap);
 
        /*
         * current_threshold points to threshold just below or equal to usage.
@@ -4673,10 +4720,10 @@ static int __mem_cgroup_usage_register_event(struct mem_cgroup *memcg,
 
        if (type == _MEM) {
                thresholds = &memcg->thresholds;
-               usage = res_counter_read_u64(&memcg->res, RES_USAGE);
+               usage = mem_cgroup_usage(memcg, false);
        } else if (type == _MEMSWAP) {
                thresholds = &memcg->memsw_thresholds;
-               usage = res_counter_read_u64(&memcg->memsw, RES_USAGE);
+               usage = mem_cgroup_usage(memcg, true);
        } else
                BUG();
 
@@ -4762,10 +4809,10 @@ static void __mem_cgroup_usage_unregister_event(struct mem_cgroup *memcg,
 
        if (type == _MEM) {
                thresholds = &memcg->thresholds;
-               usage = res_counter_read_u64(&memcg->res, RES_USAGE);
+               usage = mem_cgroup_usage(memcg, false);
        } else if (type == _MEMSWAP) {
                thresholds = &memcg->memsw_thresholds;
-               usage = res_counter_read_u64(&memcg->memsw, RES_USAGE);
+               usage = mem_cgroup_usage(memcg, true);
        } else
                BUG();
 
@@ -5525,9 +5572,9 @@ mem_cgroup_css_online(struct cgroup_subsys_state *css)
                 * core guarantees its existence.
                 */
        } else {
-               res_counter_init(&memcg->res, &root_mem_cgroup->res);
-               res_counter_init(&memcg->memsw, &root_mem_cgroup->memsw);
-               res_counter_init(&memcg->kmem, &root_mem_cgroup->kmem);
+               res_counter_init(&memcg->res, NULL);
+               res_counter_init(&memcg->memsw, NULL);
+               res_counter_init(&memcg->kmem, NULL);
                /*
                 * Deeper hierachy with use_hierarchy == false doesn't make
                 * much sense so let cgroup subsystem know about this
@@ -5969,8 +6016,9 @@ static void __mem_cgroup_clear_mc(void)
        /* we must fixup refcnts and charges */
        if (mc.moved_swap) {
                /* uncharge swap account from the old cgroup */
-               res_counter_uncharge(&mc.from->memsw,
-                                    PAGE_SIZE * mc.moved_swap);
+               if (!mem_cgroup_is_root(mc.from))
+                       res_counter_uncharge(&mc.from->memsw,
+                                            PAGE_SIZE * mc.moved_swap);
 
                for (i = 0; i < mc.moved_swap; i++)
                        css_put(&mc.from->css);
@@ -5979,8 +6027,9 @@ static void __mem_cgroup_clear_mc(void)
                 * we charged both to->res and to->memsw, so we should
                 * uncharge to->res.
                 */
-               res_counter_uncharge(&mc.to->res,
-                                    PAGE_SIZE * mc.moved_swap);
+               if (!mem_cgroup_is_root(mc.to))
+                       res_counter_uncharge(&mc.to->res,
+                                            PAGE_SIZE * mc.moved_swap);
                /* we've already done css_get(mc.to) */
                mc.moved_swap = 0;
        }
@@ -6345,7 +6394,8 @@ void mem_cgroup_uncharge_swap(swp_entry_t entry)
        rcu_read_lock();
        memcg = mem_cgroup_lookup(id);
        if (memcg) {
-               res_counter_uncharge(&memcg->memsw, PAGE_SIZE);
+               if (!mem_cgroup_is_root(memcg))
+                       res_counter_uncharge(&memcg->memsw, PAGE_SIZE);
                mem_cgroup_swap_statistics(memcg, false);
                css_put(&memcg->css);
        }
@@ -6509,12 +6559,15 @@ static void uncharge_batch(struct mem_cgroup *memcg, unsigned long pgpgout,
 {
        unsigned long flags;
 
-       if (nr_mem)
-               res_counter_uncharge(&memcg->res, nr_mem * PAGE_SIZE);
-       if (nr_memsw)
-               res_counter_uncharge(&memcg->memsw, nr_memsw * PAGE_SIZE);
-
-       memcg_oom_recover(memcg);
+       if (!mem_cgroup_is_root(memcg)) {
+               if (nr_mem)
+                       res_counter_uncharge(&memcg->res,
+                                            nr_mem * PAGE_SIZE);
+               if (nr_memsw)
+                       res_counter_uncharge(&memcg->memsw,
+                                            nr_memsw * PAGE_SIZE);
+               memcg_oom_recover(memcg);
+       }
 
        local_irq_save(flags);
        __this_cpu_sub(memcg->stat->count[MEM_CGROUP_STAT_RSS], nr_anon);
index ab3537bcfed2334fd1636cfc8e74ff634e54c943..adeac306610f7d7895e9d361d11649fb31f0a914 100644 (file)
@@ -751,7 +751,7 @@ struct page *vm_normal_page(struct vm_area_struct *vma, unsigned long addr,
        unsigned long pfn = pte_pfn(pte);
 
        if (HAVE_PTE_SPECIAL) {
-               if (likely(!pte_special(pte) || pte_numa(pte)))
+               if (likely(!pte_special(pte)))
                        goto check_pfn;
                if (vma->vm_flags & (VM_PFNMAP | VM_MIXEDMAP))
                        return NULL;
@@ -777,15 +777,14 @@ struct page *vm_normal_page(struct vm_area_struct *vma, unsigned long addr,
                }
        }
 
+       if (is_zero_pfn(pfn))
+               return NULL;
 check_pfn:
        if (unlikely(pfn > highest_memmap_pfn)) {
                print_bad_pte(vma, addr, pte, NULL);
                return NULL;
        }
 
-       if (is_zero_pfn(pfn))
-               return NULL;
-
        /*
         * NOTE! We still have PageReserved() pages in the page tables.
         * eg. VDSO mappings can cause them to exist.
index 3707c71ae4cddbec027eac857291185c662c760a..51108165f829d777e4c69abe6109cb88ca4d7e14 100644 (file)
@@ -108,7 +108,7 @@ static int pcpu_alloc_pages(struct pcpu_chunk *chunk,
                            int page_start, int page_end)
 {
        const gfp_t gfp = GFP_KERNEL | __GFP_HIGHMEM | __GFP_COLD;
-       unsigned int cpu;
+       unsigned int cpu, tcpu;
        int i;
 
        for_each_possible_cpu(cpu) {
@@ -116,14 +116,23 @@ static int pcpu_alloc_pages(struct pcpu_chunk *chunk,
                        struct page **pagep = &pages[pcpu_page_idx(cpu, i)];
 
                        *pagep = alloc_pages_node(cpu_to_node(cpu), gfp, 0);
-                       if (!*pagep) {
-                               pcpu_free_pages(chunk, pages, populated,
-                                               page_start, page_end);
-                               return -ENOMEM;
-                       }
+                       if (!*pagep)
+                               goto err;
                }
        }
        return 0;
+
+err:
+       while (--i >= page_start)
+               __free_page(pages[pcpu_page_idx(cpu, i)]);
+
+       for_each_possible_cpu(tcpu) {
+               if (tcpu == cpu)
+                       break;
+               for (i = page_start; i < page_end; i++)
+                       __free_page(pages[pcpu_page_idx(tcpu, i)]);
+       }
+       return -ENOMEM;
 }
 
 /**
@@ -263,6 +272,7 @@ err:
                __pcpu_unmap_pages(pcpu_chunk_addr(chunk, tcpu, page_start),
                                   page_end - page_start);
        }
+       pcpu_post_unmap_tlb_flush(chunk, page_start, page_end);
        return err;
 }
 
index 2139e30a4b4490da90c2e2811d5ecc901ff07d61..da997f9800bdeab14b47b694b09593de89db4a17 100644 (file)
@@ -1932,6 +1932,8 @@ void __init setup_per_cpu_areas(void)
 
        if (pcpu_setup_first_chunk(ai, fc) < 0)
                panic("Failed to initialize percpu areas.");
+
+       pcpu_free_alloc_info(ai);
 }
 
 #endif /* CONFIG_SMP */
index a8b9199259342df9cafb84be53010eb2206ebece..dfb79e028ecbf225c626d971179954a4918b646e 100644 (file)
@@ -195,7 +195,7 @@ void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address,
        pmd_t entry = *pmdp;
        if (pmd_numa(entry))
                entry = pmd_mknonnuma(entry);
-       set_pmd_at(vma->vm_mm, address, pmdp, pmd_mknotpresent(*pmdp));
+       set_pmd_at(vma->vm_mm, address, pmdp, pmd_mknotpresent(entry));
        flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
 }
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
index a05790b1915eb4faba938cd0264c8a5ccfd2aa9e..f26e7fcc7fa25c7316f60235e8c402ff6bec4f26 100644 (file)
--- a/mm/zbud.c
+++ b/mm/zbud.c
@@ -195,6 +195,7 @@ static struct zpool_driver zbud_zpool_driver = {
        .total_size =   zbud_zpool_total_size,
 };
 
+MODULE_ALIAS("zpool-zbud");
 #endif /* CONFIG_ZPOOL */
 
 /*****************
index e40612a1df00b62c9a9728867d45fd7275bb2b0f..739cdf0d183ac0e51571d16f5b6321ccc837e7d1 100644 (file)
@@ -150,7 +150,7 @@ struct zpool *zpool_create_pool(char *type, gfp_t gfp, struct zpool_ops *ops)
        driver = zpool_get_driver(type);
 
        if (!driver) {
-               request_module(type);
+               request_module("zpool-%s", type);
                driver = zpool_get_driver(type);
        }
 
index 4e2fc83cb394b9b53384fdc82288e7b6ab793b3a..94f38fac5e81eb451d61e6561000c354103c0589 100644 (file)
@@ -315,6 +315,7 @@ static struct zpool_driver zs_zpool_driver = {
        .total_size =   zs_zpool_total_size,
 };
 
+MODULE_ALIAS("zpool-zsmalloc");
 #endif /* CONFIG_ZPOOL */
 
 /* per-cpu VM mapping areas for zspage accesses that cross page boundaries */
index 46339040fef014771e504803eef23356c6a1a9f4..1d9eaa4f041a143fa4ef13edcbb54b35f150659a 100644 (file)
@@ -384,7 +384,7 @@ static netdev_tx_t clip_start_xmit(struct sk_buff *skb,
        pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, vcc, vcc->dev);
        old = xchg(&entry->vccs->xoff, 1);      /* assume XOFF ... */
        if (old) {
-               pr_warning("XOFF->XOFF transition\n");
+               pr_warn("XOFF->XOFF transition\n");
                goto out_release_neigh;
        }
        dev->stats.tx_packets++;
@@ -447,7 +447,7 @@ static int clip_setentry(struct atm_vcc *vcc, __be32 ip)
        struct rtable *rt;
 
        if (vcc->push != clip_push) {
-               pr_warning("non-CLIP VCC\n");
+               pr_warn("non-CLIP VCC\n");
                return -EBADF;
        }
        clip_vcc = CLIP_VCC(vcc);
index 7b491006eaf4000424282979b0c4709325102152..6a765156a3f6b81fcd63f43504d1a7faca8f206b 100644 (file)
@@ -300,7 +300,7 @@ static int adjust_tp(struct atm_trafprm *tp, unsigned char aal)
                max_sdu = ATM_MAX_AAL34_PDU;
                break;
        default:
-               pr_warning("AAL problems ... (%d)\n", aal);
+               pr_warn("AAL problems ... (%d)\n", aal);
                /* fall through */
        case ATM_AAL5:
                max_sdu = ATM_MAX_AAL5_PDU;
index e4853b50cf402d9606c49daf34bc849467dab391..4b98f897044aa6a364392bc1ec5b68a2a672a2d2 100644 (file)
@@ -410,9 +410,11 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
                priv->lane2_ops = NULL;
                if (priv->lane_version > 1)
                        priv->lane2_ops = &lane2_ops;
+               rtnl_lock();
                if (dev_set_mtu(dev, mesg->content.config.mtu))
                        pr_info("%s: change_mtu to %d failed\n",
                                dev->name, mesg->content.config.mtu);
+               rtnl_unlock();
                priv->is_proxy = mesg->content.config.is_proxy;
                break;
        case l_flush_tran_id:
index e8e0e7a8a23d12029440b2f01b1c10b6e6326f27..0e982222d4255dbbc5ec9818e65af1145e086a03 100644 (file)
@@ -599,7 +599,7 @@ static netdev_tx_t mpc_send_packet(struct sk_buff *skb,
        }
 
 non_ip:
-       return mpc->old_ops->ndo_start_xmit(skb, dev);
+       return __netdev_start_xmit(mpc->old_ops, skb, dev, false);
 }
 
 static int atm_mpoa_vcc_attach(struct atm_vcc *vcc, void __user *arg)
index 52c43f9042209deaba0be22b549724ad28de1a77..fc1835c6bb4099e50e75f964826b0aacdd7200f0 100644 (file)
@@ -188,7 +188,7 @@ static bool batadv_frag_insert_packet(struct batadv_orig_node *orig_node,
 
        /* Reached the end of the list, so insert after 'frag_entry_last'. */
        if (likely(frag_entry_last)) {
-               hlist_add_behind(&frag_entry_last->list, &frag_entry_new->list);
+               hlist_add_behind(&frag_entry_new->list, &frag_entry_last->list);
                chain->size += skb->len - hdr_size;
                chain->timestamp = jiffies;
                ret = true;
index 206b65ccd5b8bd318e554e452966fae1c582112f..35ebe79c87b0ca5df9a76ad0ea7761c433cf1fe0 100644 (file)
@@ -772,16 +772,16 @@ static inline void chan_ready_cb(struct l2cap_chan *chan)
        ifup(dev->netdev);
 }
 
-static inline struct l2cap_chan *chan_new_conn_cb(struct l2cap_chan *chan)
+static inline struct l2cap_chan *chan_new_conn_cb(struct l2cap_chan *pchan)
 {
-       struct l2cap_chan *pchan;
+       struct l2cap_chan *chan;
 
-       pchan = chan_open(chan);
-       pchan->ops = chan->ops;
+       chan = chan_open(pchan);
+       chan->ops = pchan->ops;
 
        BT_DBG("chan %p pchan %p", chan, pchan);
 
-       return pchan;
+       return chan;
 }
 
 static void delete_netdev(struct work_struct *work)
index b50dabb3f86ab49667cb939af29cef53a03b2ac2..faff6247ac8fb8769bf58f235fd92c0deab6aaf1 100644 (file)
@@ -589,6 +589,14 @@ EXPORT_SYMBOL(hci_get_route);
 void hci_le_conn_failed(struct hci_conn *conn, u8 status)
 {
        struct hci_dev *hdev = conn->hdev;
+       struct hci_conn_params *params;
+
+       params = hci_pend_le_action_lookup(&hdev->pend_le_conns, &conn->dst,
+                                          conn->dst_type);
+       if (params && params->conn) {
+               hci_conn_drop(params->conn);
+               params->conn = NULL;
+       }
 
        conn->state = BT_CLOSED;
 
index c32d361c0cf766478f80fb9ed8a4884f53451122..9b7145959a49e7ea7b52cf7fb11e9a8f68fa7346 100644 (file)
@@ -1898,6 +1898,8 @@ static int __hci_init(struct hci_dev *hdev)
                debugfs_create_u16("discov_interleaved_timeout", 0644,
                                   hdev->debugfs,
                                   &hdev->discov_interleaved_timeout);
+
+               smp_register(hdev);
        }
 
        return 0;
@@ -2536,8 +2538,13 @@ static void hci_pend_le_actions_clear(struct hci_dev *hdev)
 {
        struct hci_conn_params *p;
 
-       list_for_each_entry(p, &hdev->le_conn_params, list)
+       list_for_each_entry(p, &hdev->le_conn_params, list) {
+               if (p->conn) {
+                       hci_conn_drop(p->conn);
+                       p->conn = NULL;
+               }
                list_del_init(&p->action);
+       }
 
        BT_DBG("All LE pending actions cleared");
 }
@@ -2578,8 +2585,8 @@ static int hci_dev_do_close(struct hci_dev *hdev)
 
        hci_dev_lock(hdev);
        hci_inquiry_cache_flush(hdev);
-       hci_conn_hash_flush(hdev);
        hci_pend_le_actions_clear(hdev);
+       hci_conn_hash_flush(hdev);
        hci_dev_unlock(hdev);
 
        hci_notify(hdev, HCI_DEV_DOWN);
@@ -3233,7 +3240,7 @@ struct smp_irk *hci_find_irk_by_rpa(struct hci_dev *hdev, bdaddr_t *rpa)
        }
 
        list_for_each_entry(irk, &hdev->identity_resolving_keys, list) {
-               if (smp_irk_matches(hdev->tfm_aes, irk->val, rpa)) {
+               if (smp_irk_matches(hdev, irk->val, rpa)) {
                        bacpy(&irk->rpa, rpa);
                        return irk;
                }
@@ -3727,6 +3734,9 @@ void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type)
        if (!params)
                return;
 
+       if (params->conn)
+               hci_conn_drop(params->conn);
+
        list_del(&params->action);
        list_del(&params->list);
        kfree(params);
@@ -3757,6 +3767,8 @@ void hci_conn_params_clear_all(struct hci_dev *hdev)
        struct hci_conn_params *params, *tmp;
 
        list_for_each_entry_safe(params, tmp, &hdev->le_conn_params, list) {
+               if (params->conn)
+                       hci_conn_drop(params->conn);
                list_del(&params->action);
                list_del(&params->list);
                kfree(params);
@@ -3882,7 +3894,7 @@ int hci_update_random_address(struct hci_request *req, bool require_privacy,
                    !bacmp(&hdev->random_addr, &hdev->rpa))
                        return 0;
 
-               err = smp_generate_rpa(hdev->tfm_aes, hdev->irk, &hdev->rpa);
+               err = smp_generate_rpa(hdev, hdev->irk, &hdev->rpa);
                if (err < 0) {
                        BT_ERR("%s failed to generate new RPA", hdev->name);
                        return err;
@@ -4090,18 +4102,9 @@ int hci_register_dev(struct hci_dev *hdev)
 
        dev_set_name(&hdev->dev, "%s", hdev->name);
 
-       hdev->tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0,
-                                              CRYPTO_ALG_ASYNC);
-       if (IS_ERR(hdev->tfm_aes)) {
-               BT_ERR("Unable to create crypto context");
-               error = PTR_ERR(hdev->tfm_aes);
-               hdev->tfm_aes = NULL;
-               goto err_wqueue;
-       }
-
        error = device_add(&hdev->dev);
        if (error < 0)
-               goto err_tfm;
+               goto err_wqueue;
 
        hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev,
                                    RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops,
@@ -4143,8 +4146,6 @@ int hci_register_dev(struct hci_dev *hdev)
 
        return id;
 
-err_tfm:
-       crypto_free_blkcipher(hdev->tfm_aes);
 err_wqueue:
        destroy_workqueue(hdev->workqueue);
        destroy_workqueue(hdev->req_workqueue);
@@ -4196,8 +4197,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
                rfkill_destroy(hdev->rfkill);
        }
 
-       if (hdev->tfm_aes)
-               crypto_free_blkcipher(hdev->tfm_aes);
+       smp_unregister(hdev);
 
        device_del(&hdev->dev);
 
@@ -5680,3 +5680,52 @@ void hci_update_background_scan(struct hci_dev *hdev)
        if (err)
                BT_ERR("Failed to run HCI request: err %d", err);
 }
+
+static bool disconnected_whitelist_entries(struct hci_dev *hdev)
+{
+       struct bdaddr_list *b;
+
+       list_for_each_entry(b, &hdev->whitelist, list) {
+               struct hci_conn *conn;
+
+               conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &b->bdaddr);
+               if (!conn)
+                       return true;
+
+               if (conn->state != BT_CONNECTED && conn->state != BT_CONFIG)
+                       return true;
+       }
+
+       return false;
+}
+
+void hci_update_page_scan(struct hci_dev *hdev, struct hci_request *req)
+{
+       u8 scan;
+
+       if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
+               return;
+
+       if (!hdev_is_powered(hdev))
+               return;
+
+       if (mgmt_powering_down(hdev))
+               return;
+
+       if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags) ||
+           disconnected_whitelist_entries(hdev))
+               scan = SCAN_PAGE;
+       else
+               scan = SCAN_DISABLED;
+
+       if (test_bit(HCI_PSCAN, &hdev->flags) == !!(scan & SCAN_PAGE))
+               return;
+
+       if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
+               scan |= SCAN_INQUIRY;
+
+       if (req)
+               hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
+       else
+               hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
+}
index be35598984d9b9b3120cd178f67f0418858b2774..3a99f30a3317e91955f29d6c1d783f02ece75398 100644 (file)
@@ -2071,6 +2071,8 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
                        cp.handle = ev->handle;
                        hci_send_cmd(hdev, HCI_OP_READ_REMOTE_FEATURES,
                                     sizeof(cp), &cp);
+
+                       hci_update_page_scan(hdev, NULL);
                }
 
                /* Set packet type for incoming connection */
@@ -2247,9 +2249,12 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
        mgmt_device_disconnected(hdev, &conn->dst, conn->type, conn->dst_type,
                                reason, mgmt_connected);
 
-       if (conn->type == ACL_LINK &&
-           test_bit(HCI_CONN_FLUSH_KEY, &conn->flags))
-               hci_remove_link_key(hdev, &conn->dst);
+       if (conn->type == ACL_LINK) {
+               if (test_bit(HCI_CONN_FLUSH_KEY, &conn->flags))
+                       hci_remove_link_key(hdev, &conn->dst);
+
+               hci_update_page_scan(hdev, NULL);
+       }
 
        params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type);
        if (params) {
@@ -4221,8 +4226,13 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
        hci_proto_connect_cfm(conn, ev->status);
 
        params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type);
-       if (params)
+       if (params) {
                list_del_init(&params->action);
+               if (params->conn) {
+                       hci_conn_drop(params->conn);
+                       params->conn = NULL;
+               }
+       }
 
 unlock:
        hci_update_background_scan(hdev);
@@ -4304,8 +4314,16 @@ static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr,
 
        conn = hci_connect_le(hdev, addr, addr_type, BT_SECURITY_LOW,
                              HCI_LE_AUTOCONN_TIMEOUT, HCI_ROLE_MASTER);
-       if (!IS_ERR(conn))
+       if (!IS_ERR(conn)) {
+               /* Store the pointer since we don't really have any
+                * other owner of the object besides the params that
+                * triggered it. This way we can abort the connection if
+                * the parameters get removed and keep the reference
+                * count consistent once the connection is established.
+                */
+               params->conn = conn;
                return;
+       }
 
        switch (PTR_ERR(conn)) {
        case -EBUSY:
index 46547b920f88edf7e6df5b6c5d10ae30daa47d67..4a90438d99dff0c8c660e1ce66c8f7ad9a67dc58 100644 (file)
@@ -210,6 +210,10 @@ int l2cap_add_scid(struct l2cap_chan *chan,  __u16 scid)
 {
        write_lock(&chan_list_lock);
 
+       /* Override the defaults (which are for conn-oriented) */
+       chan->omtu = L2CAP_DEFAULT_MTU;
+       chan->chan_type = L2CAP_CHAN_FIXED;
+
        chan->scid = scid;
 
        write_unlock(&chan_list_lock);
@@ -562,6 +566,8 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
 
        BT_DBG("chan %p, conn %p, err %d", chan, conn, err);
 
+       chan->ops->teardown(chan, err);
+
        if (conn) {
                struct amp_mgr *mgr = conn->hcon->amp_mgr;
                /* Delete from channel list */
@@ -585,8 +591,6 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
                amp_disconnect_logical_link(hs_hchan);
        }
 
-       chan->ops->teardown(chan, err);
-
        if (test_bit(CONF_NOT_COMPLETE, &chan->conf_state))
                return;
 
@@ -1082,6 +1086,9 @@ static void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, bool poll)
 
 static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
 {
+       if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED)
+               return true;
+
        return !test_bit(CONF_CONNECT_PEND, &chan->conf_state);
 }
 
@@ -1417,71 +1424,18 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
        mutex_unlock(&conn->chan_lock);
 }
 
-/* Find socket with cid and source/destination bdaddr.
- * Returns closest match, locked.
- */
-static struct l2cap_chan *l2cap_global_chan_by_scid(int state, u16 cid,
-                                                   bdaddr_t *src,
-                                                   bdaddr_t *dst)
-{
-       struct l2cap_chan *c, *c1 = NULL;
-
-       read_lock(&chan_list_lock);
-
-       list_for_each_entry(c, &chan_list, global_l) {
-               if (state && c->state != state)
-                       continue;
-
-               if (c->scid == cid) {
-                       int src_match, dst_match;
-                       int src_any, dst_any;
-
-                       /* Exact match. */
-                       src_match = !bacmp(&c->src, src);
-                       dst_match = !bacmp(&c->dst, dst);
-                       if (src_match && dst_match) {
-                               read_unlock(&chan_list_lock);
-                               return c;
-                       }
-
-                       /* Closest match */
-                       src_any = !bacmp(&c->src, BDADDR_ANY);
-                       dst_any = !bacmp(&c->dst, BDADDR_ANY);
-                       if ((src_match && dst_any) || (src_any && dst_match) ||
-                           (src_any && dst_any))
-                               c1 = c;
-               }
-       }
-
-       read_unlock(&chan_list_lock);
-
-       return c1;
-}
-
 static void l2cap_le_conn_ready(struct l2cap_conn *conn)
 {
        struct hci_conn *hcon = conn->hcon;
        struct hci_dev *hdev = hcon->hdev;
-       struct l2cap_chan *chan, *pchan;
-       u8 dst_type;
 
-       BT_DBG("");
+       BT_DBG("%s conn %p", hdev->name, conn);
 
-       /* Check if we have socket listening on cid */
-       pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_ATT,
-                                         &hcon->src, &hcon->dst);
-       if (!pchan)
-               return;
-
-       /* Client ATT sockets should override the server one */
-       if (__l2cap_get_chan_by_dcid(conn, L2CAP_CID_ATT))
-               return;
-
-       dst_type = bdaddr_type(hcon, hcon->dst_type);
-
-       /* If device is blocked, do not create a channel for it */
-       if (hci_bdaddr_list_lookup(&hdev->blacklist, &hcon->dst, dst_type))
-               return;
+       /* For outgoing pairing which doesn't necessarily have an
+        * associated socket (e.g. mgmt_pair_device).
+        */
+       if (hcon->out)
+               smp_conn_security(hcon, hcon->pending_sec_level);
 
        /* For LE slave connections, make sure the connection interval
         * is in the range of the minium and maximum interval that has
@@ -1501,22 +1455,6 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
                l2cap_send_cmd(conn, l2cap_get_ident(conn),
                               L2CAP_CONN_PARAM_UPDATE_REQ, sizeof(req), &req);
        }
-
-       l2cap_chan_lock(pchan);
-
-       chan = pchan->ops->new_connection(pchan);
-       if (!chan)
-               goto clean;
-
-       bacpy(&chan->src, &hcon->src);
-       bacpy(&chan->dst, &hcon->dst);
-       chan->src_type = bdaddr_type(hcon, hcon->src_type);
-       chan->dst_type = dst_type;
-
-       __l2cap_chan_add(conn, chan);
-
-clean:
-       l2cap_chan_unlock(pchan);
 }
 
 static void l2cap_conn_ready(struct l2cap_conn *conn)
@@ -1526,17 +1464,8 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
 
        BT_DBG("conn %p", conn);
 
-       /* For outgoing pairing which doesn't necessarily have an
-        * associated socket (e.g. mgmt_pair_device).
-        */
-       if (hcon->out && hcon->type == LE_LINK)
-               smp_conn_security(hcon, hcon->pending_sec_level);
-
        mutex_lock(&conn->chan_lock);
 
-       if (hcon->type == LE_LINK)
-               l2cap_le_conn_ready(conn);
-
        list_for_each_entry(chan, &conn->chan_l, list) {
 
                l2cap_chan_lock(chan);
@@ -1560,6 +1489,9 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
 
        mutex_unlock(&conn->chan_lock);
 
+       if (hcon->type == LE_LINK)
+               l2cap_le_conn_ready(conn);
+
        queue_work(hcon->hdev->workqueue, &conn->pending_rx_work);
 }
 
@@ -1695,6 +1627,9 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
        if (work_pending(&conn->pending_rx_work))
                cancel_work_sync(&conn->pending_rx_work);
 
+       if (work_pending(&conn->disconn_work))
+               cancel_work_sync(&conn->disconn_work);
+
        l2cap_unregister_all_users(conn);
 
        mutex_lock(&conn->chan_lock);
@@ -1719,27 +1654,29 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
        if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
                cancel_delayed_work_sync(&conn->info_timer);
 
-       if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) {
-               cancel_delayed_work_sync(&conn->security_timer);
-               smp_chan_destroy(conn);
-       }
-
        hcon->l2cap_data = NULL;
        conn->hchan = NULL;
        l2cap_conn_put(conn);
 }
 
-static void security_timeout(struct work_struct *work)
+static void disconn_work(struct work_struct *work)
 {
        struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
-                                              security_timer.work);
+                                              disconn_work);
 
        BT_DBG("conn %p", conn);
 
-       if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) {
-               smp_chan_destroy(conn);
-               l2cap_conn_del(conn->hcon, ETIMEDOUT);
-       }
+       l2cap_conn_del(conn->hcon, conn->disconn_err);
+}
+
+void l2cap_conn_shutdown(struct l2cap_conn *conn, int err)
+{
+       struct hci_dev *hdev = conn->hcon->hdev;
+
+       BT_DBG("conn %p err %d", conn, err);
+
+       conn->disconn_err = err;
+       queue_work(hdev->workqueue, &conn->disconn_work);
 }
 
 static void l2cap_conn_free(struct kref *ref)
@@ -1794,6 +1731,7 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm,
                        src_match = !bacmp(&c->src, src);
                        dst_match = !bacmp(&c->dst, dst);
                        if (src_match && dst_match) {
+                               l2cap_chan_hold(c);
                                read_unlock(&chan_list_lock);
                                return c;
                        }
@@ -1807,6 +1745,9 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm,
                }
        }
 
+       if (c1)
+               l2cap_chan_hold(c1);
+
        read_unlock(&chan_list_lock);
 
        return c1;
@@ -2027,10 +1968,12 @@ static void l2cap_ertm_resend(struct l2cap_chan *chan)
                                           tx_skb->data + L2CAP_HDR_SIZE);
                }
 
+               /* Update FCS */
                if (chan->fcs == L2CAP_FCS_CRC16) {
-                       u16 fcs = crc16(0, (u8 *) tx_skb->data, tx_skb->len);
-                       put_unaligned_le16(fcs, skb_put(tx_skb,
-                                                       L2CAP_FCS_SIZE));
+                       u16 fcs = crc16(0, (u8 *) tx_skb->data,
+                                       tx_skb->len - L2CAP_FCS_SIZE);
+                       put_unaligned_le16(fcs, skb_tail_pointer(tx_skb) -
+                                               L2CAP_FCS_SIZE);
                }
 
                l2cap_do_send(chan, tx_skb);
@@ -2334,7 +2277,6 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan,
        } else {
                sar = L2CAP_SAR_START;
                sdu_len = len;
-               pdu_len -= L2CAP_SDULEN_SIZE;
        }
 
        while (len > 0) {
@@ -2349,10 +2291,8 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan,
                __skb_queue_tail(seg_queue, skb);
 
                len -= pdu_len;
-               if (sdu_len) {
+               if (sdu_len)
                        sdu_len = 0;
-                       pdu_len += L2CAP_SDULEN_SIZE;
-               }
 
                if (len <= pdu_len) {
                        sar = L2CAP_SAR_END;
@@ -3884,6 +3824,7 @@ static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn,
 response:
        l2cap_chan_unlock(pchan);
        mutex_unlock(&conn->chan_lock);
+       l2cap_chan_put(pchan);
 
 sendresp:
        rsp.scid   = cpu_to_le16(scid);
@@ -5497,6 +5438,7 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
 response_unlock:
        l2cap_chan_unlock(pchan);
        mutex_unlock(&conn->chan_lock);
+       l2cap_chan_put(pchan);
 
        if (result == L2CAP_CR_PEND)
                return 0;
@@ -6845,12 +6787,12 @@ static void l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm,
        struct l2cap_chan *chan;
 
        if (hcon->type != ACL_LINK)
-               goto drop;
+               goto free_skb;
 
        chan = l2cap_global_chan_by_psm(0, psm, &hcon->src, &hcon->dst,
                                        ACL_LINK);
        if (!chan)
-               goto drop;
+               goto free_skb;
 
        BT_DBG("chan %p, len %d", chan, skb->len);
 
@@ -6864,36 +6806,14 @@ static void l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm,
        bacpy(&bt_cb(skb)->bdaddr, &hcon->dst);
        bt_cb(skb)->psm = psm;
 
-       if (!chan->ops->recv(chan, skb))
-               return;
-
-drop:
-       kfree_skb(skb);
-}
-
-static void l2cap_att_channel(struct l2cap_conn *conn,
-                             struct sk_buff *skb)
-{
-       struct hci_conn *hcon = conn->hcon;
-       struct l2cap_chan *chan;
-
-       if (hcon->type != LE_LINK)
-               goto drop;
-
-       chan = l2cap_global_chan_by_scid(BT_CONNECTED, L2CAP_CID_ATT,
-                                        &hcon->src, &hcon->dst);
-       if (!chan)
-               goto drop;
-
-       BT_DBG("chan %p, len %d", chan, skb->len);
-
-       if (chan->imtu < skb->len)
-               goto drop;
-
-       if (!chan->ops->recv(chan, skb))
+       if (!chan->ops->recv(chan, skb)) {
+               l2cap_chan_put(chan);
                return;
+       }
 
 drop:
+       l2cap_chan_put(chan);
+free_skb:
        kfree_skb(skb);
 }
 
@@ -6942,19 +6862,10 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
                l2cap_conless_channel(conn, psm, skb);
                break;
 
-       case L2CAP_CID_ATT:
-               l2cap_att_channel(conn, skb);
-               break;
-
        case L2CAP_CID_LE_SIGNALING:
                l2cap_le_sig_channel(conn, skb);
                break;
 
-       case L2CAP_CID_SMP:
-               if (smp_sig_channel(conn, skb))
-                       l2cap_conn_del(conn->hcon, EACCES);
-               break;
-
        default:
                l2cap_data_channel(conn, cid, skb);
                break;
@@ -7023,10 +6934,9 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon)
        INIT_LIST_HEAD(&conn->chan_l);
        INIT_LIST_HEAD(&conn->users);
 
-       if (hcon->type == LE_LINK)
-               INIT_DELAYED_WORK(&conn->security_timer, security_timeout);
-       else
-               INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout);
+       INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout);
+
+       INIT_WORK(&conn->disconn_work, disconn_work);
 
        skb_queue_head_init(&conn->pending_rx);
        INIT_WORK(&conn->pending_rx_work, process_pending_rx);
@@ -7239,19 +7149,99 @@ int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
        return exact ? lm1 : lm2;
 }
 
+/* Find the next fixed channel in BT_LISTEN state, continue iteration
+ * from an existing channel in the list or from the beginning of the
+ * global list (by passing NULL as first parameter).
+ */
+static struct l2cap_chan *l2cap_global_fixed_chan(struct l2cap_chan *c,
+                                                 bdaddr_t *src, u8 link_type)
+{
+       read_lock(&chan_list_lock);
+
+       if (c)
+               c = list_next_entry(c, global_l);
+       else
+               c = list_entry(chan_list.next, typeof(*c), global_l);
+
+       list_for_each_entry_from(c, &chan_list, global_l) {
+               if (c->chan_type != L2CAP_CHAN_FIXED)
+                       continue;
+               if (c->state != BT_LISTEN)
+                       continue;
+               if (bacmp(&c->src, src) && bacmp(&c->src, BDADDR_ANY))
+                       continue;
+               if (link_type == ACL_LINK && c->src_type != BDADDR_BREDR)
+                       continue;
+               if (link_type == LE_LINK && c->src_type == BDADDR_BREDR)
+                       continue;
+
+               l2cap_chan_hold(c);
+               read_unlock(&chan_list_lock);
+               return c;
+       }
+
+       read_unlock(&chan_list_lock);
+
+       return NULL;
+}
+
 void l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
 {
+       struct hci_dev *hdev = hcon->hdev;
        struct l2cap_conn *conn;
+       struct l2cap_chan *pchan;
+       u8 dst_type;
 
        BT_DBG("hcon %p bdaddr %pMR status %d", hcon, &hcon->dst, status);
 
-       if (!status) {
-               conn = l2cap_conn_add(hcon);
-               if (conn)
-                       l2cap_conn_ready(conn);
-       } else {
+       if (status) {
                l2cap_conn_del(hcon, bt_to_errno(status));
+               return;
        }
+
+       conn = l2cap_conn_add(hcon);
+       if (!conn)
+               return;
+
+       dst_type = bdaddr_type(hcon, hcon->dst_type);
+
+       /* If device is blocked, do not create channels for it */
+       if (hci_bdaddr_list_lookup(&hdev->blacklist, &hcon->dst, dst_type))
+               return;
+
+       /* Find fixed channels and notify them of the new connection. We
+        * use multiple individual lookups, continuing each time where
+        * we left off, because the list lock would prevent calling the
+        * potentially sleeping l2cap_chan_lock() function.
+        */
+       pchan = l2cap_global_fixed_chan(NULL, &hdev->bdaddr, hcon->type);
+       while (pchan) {
+               struct l2cap_chan *chan, *next;
+
+               /* Client fixed channels should override server ones */
+               if (__l2cap_get_chan_by_dcid(conn, pchan->scid))
+                       goto next;
+
+               l2cap_chan_lock(pchan);
+               chan = pchan->ops->new_connection(pchan);
+               if (chan) {
+                       bacpy(&chan->src, &hcon->src);
+                       bacpy(&chan->dst, &hcon->dst);
+                       chan->src_type = bdaddr_type(hcon, hcon->src_type);
+                       chan->dst_type = dst_type;
+
+                       __l2cap_chan_add(conn, chan);
+               }
+
+               l2cap_chan_unlock(pchan);
+next:
+               next = l2cap_global_fixed_chan(pchan, &hdev->bdaddr,
+                                              hcon->type);
+               l2cap_chan_put(pchan);
+               pchan = next;
+       }
+
+       l2cap_conn_ready(conn);
 }
 
 int l2cap_disconn_ind(struct hci_conn *hcon)
@@ -7299,12 +7289,6 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
 
        BT_DBG("conn %p status 0x%2.2x encrypt %u", conn, status, encrypt);
 
-       if (hcon->type == LE_LINK) {
-               if (!status && encrypt)
-                       smp_distribute_keys(conn);
-               cancel_delayed_work(&conn->security_timer);
-       }
-
        mutex_lock(&conn->chan_lock);
 
        list_for_each_entry(chan, &conn->chan_l, list) {
@@ -7318,15 +7302,8 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
                        continue;
                }
 
-               if (chan->scid == L2CAP_CID_ATT) {
-                       if (!status && encrypt) {
-                               chan->sec_level = hcon->sec_level;
-                               l2cap_chan_ready(chan);
-                       }
-
-                       l2cap_chan_unlock(chan);
-                       continue;
-               }
+               if (!status && encrypt)
+                       chan->sec_level = hcon->sec_level;
 
                if (!__l2cap_no_conn_pending(chan)) {
                        l2cap_chan_unlock(chan);
index 1884f72083c2f7de4595e91f2cdb61f02cef99bb..ed06f88e6f10955cae33d31a3e348b25d2c647f9 100644 (file)
@@ -99,15 +99,6 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
        if (!bdaddr_type_is_valid(la.l2_bdaddr_type))
                return -EINVAL;
 
-       if (la.l2_cid) {
-               /* When the socket gets created it defaults to
-                * CHAN_CONN_ORIENTED, so we need to overwrite the
-                * default here.
-                */
-               chan->chan_type = L2CAP_CHAN_FIXED;
-               chan->omtu = L2CAP_DEFAULT_MTU;
-       }
-
        if (bdaddr_type_is_le(la.l2_bdaddr_type)) {
                /* We only allow ATT user space socket */
                if (la.l2_cid &&
@@ -790,6 +781,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
                if (chan->scid == L2CAP_CID_ATT) {
                        if (smp_conn_security(conn->hcon, sec.level))
                                break;
+                       set_bit(FLAG_PENDING_SECURITY, &chan->flags);
                        sk->sk_state = BT_CONFIG;
                        chan->state = BT_CONFIG;
 
@@ -1359,6 +1351,11 @@ static void l2cap_sock_resume_cb(struct l2cap_chan *chan)
 {
        struct sock *sk = chan->data;
 
+       if (test_and_clear_bit(FLAG_PENDING_SECURITY, &chan->flags)) {
+               sk->sk_state = BT_CONNECTED;
+               chan->state = BT_CONNECTED;
+       }
+
        clear_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags);
        sk->sk_state_change(sk);
 }
index b8554d429d889f97bd735cc62aaafce1e85bae5c..c2457435a670149c2d368f1c81dae2697972da1f 100644 (file)
@@ -129,9 +129,6 @@ static const u16 mgmt_events[] = {
 
 #define CACHE_TIMEOUT  msecs_to_jiffies(2 * 1000)
 
-#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
-                               !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
-
 struct pending_cmd {
        struct list_head list;
        u16 opcode;
@@ -1536,9 +1533,11 @@ static void set_discoverable_complete(struct hci_dev *hdev, u8 status)
 
        /* When the discoverable mode gets changed, make sure
         * that class of device has the limited discoverable
-        * bit correctly set.
+        * bit correctly set. Also update page scan based on whitelist
+        * entries.
         */
        hci_req_init(&req, hdev);
+       hci_update_page_scan(hdev, &req);
        update_class(&req);
        hci_req_run(&req, NULL);
 
@@ -1785,6 +1784,7 @@ static void set_connectable_complete(struct hci_dev *hdev, u8 status)
 
        if (conn_changed || discov_changed) {
                new_settings(hdev, cmd->sk);
+               hci_update_page_scan(hdev, NULL);
                if (discov_changed)
                        mgmt_update_adv_data(hdev);
                hci_update_background_scan(hdev);
@@ -1818,6 +1818,7 @@ static int set_connectable_update_settings(struct hci_dev *hdev,
                return err;
 
        if (changed) {
+               hci_update_page_scan(hdev, NULL);
                hci_update_background_scan(hdev);
                return new_settings(hdev, sk);
        }
@@ -4381,27 +4382,6 @@ unlock:
        return err;
 }
 
-static void set_bredr_scan(struct hci_request *req)
-{
-       struct hci_dev *hdev = req->hdev;
-       u8 scan = 0;
-
-       /* Ensure that fast connectable is disabled. This function will
-        * not do anything if the page scan parameters are already what
-        * they should be.
-        */
-       write_fast_connectable(req, false);
-
-       if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags) ||
-           !list_empty(&hdev->whitelist))
-               scan |= SCAN_PAGE;
-       if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
-               scan |= SCAN_INQUIRY;
-
-       if (scan)
-               hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
-}
-
 static void set_bredr_complete(struct hci_dev *hdev, u8 status)
 {
        struct pending_cmd *cmd;
@@ -4507,9 +4487,8 @@ static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
 
        hci_req_init(&req, hdev);
 
-       if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags) ||
-           !list_empty(&hdev->whitelist))
-               set_bredr_scan(&req);
+       write_fast_connectable(&req, false);
+       hci_update_page_scan(hdev, &req);
 
        /* Since only the advertising data flags will change, there
         * is no need to update the scan response data.
@@ -5235,27 +5214,6 @@ unlock:
        return err;
 }
 
-/* Helper for Add/Remove Device commands */
-static void update_page_scan(struct hci_dev *hdev, u8 scan)
-{
-       if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
-               return;
-
-       if (!hdev_is_powered(hdev))
-               return;
-
-       /* If HCI_CONNECTABLE is set then Add/Remove Device should not
-        * make any changes to page scanning.
-        */
-       if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
-               return;
-
-       if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
-               scan |= SCAN_INQUIRY;
-
-       hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
-}
-
 static void device_added(struct sock *sk, struct hci_dev *hdev,
                         bdaddr_t *bdaddr, u8 type, u8 action)
 {
@@ -5291,8 +5249,6 @@ static int add_device(struct sock *sk, struct hci_dev *hdev,
        hci_dev_lock(hdev);
 
        if (cp->addr.type == BDADDR_BREDR) {
-               bool update_scan;
-
                /* Only incoming connections action is supported for now */
                if (cp->action != 0x01) {
                        err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
@@ -5301,15 +5257,12 @@ static int add_device(struct sock *sk, struct hci_dev *hdev,
                        goto unlock;
                }
 
-               update_scan = list_empty(&hdev->whitelist);
-
                err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr,
                                          cp->addr.type);
                if (err)
                        goto unlock;
 
-               if (update_scan)
-                       update_page_scan(hdev, SCAN_PAGE);
+               hci_update_page_scan(hdev, NULL);
 
                goto added;
        }
@@ -5392,8 +5345,7 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev,
                                goto unlock;
                        }
 
-                       if (list_empty(&hdev->whitelist))
-                               update_page_scan(hdev, SCAN_DISABLED);
+                       hci_update_page_scan(hdev, NULL);
 
                        device_removed(sk, hdev, &cp->addr.bdaddr,
                                       cp->addr.type);
@@ -5444,7 +5396,7 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev,
                        kfree(b);
                }
 
-               update_page_scan(hdev, SCAN_DISABLED);
+               hci_update_page_scan(hdev, NULL);
 
                list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
                        if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
@@ -5969,8 +5921,8 @@ static int powered_update_hci(struct hci_dev *hdev)
                            sizeof(link_sec), &link_sec);
 
        if (lmp_bredr_capable(hdev)) {
-               if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
-                       set_bredr_scan(&req);
+               write_fast_connectable(&req, false);
+               hci_update_page_scan(hdev, &req);
                update_class(&req);
                update_name(&req);
                update_eir(&req);
@@ -6281,25 +6233,35 @@ static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
        mgmt_pending_remove(cmd);
 }
 
+bool mgmt_powering_down(struct hci_dev *hdev)
+{
+       struct pending_cmd *cmd;
+       struct mgmt_mode *cp;
+
+       cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
+       if (!cmd)
+               return false;
+
+       cp = cmd->param;
+       if (!cp->val)
+               return true;
+
+       return false;
+}
+
 void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
                              u8 link_type, u8 addr_type, u8 reason,
                              bool mgmt_connected)
 {
        struct mgmt_ev_device_disconnected ev;
-       struct pending_cmd *power_off;
        struct sock *sk = NULL;
 
-       power_off = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
-       if (power_off) {
-               struct mgmt_mode *cp = power_off->param;
-
-               /* The connection is still in hci_conn_hash so test for 1
-                * instead of 0 to know if this is the last one.
-                */
-               if (!cp->val && hci_conn_count(hdev) == 1) {
-                       cancel_delayed_work(&hdev->power_off);
-                       queue_work(hdev->req_workqueue, &hdev->power_off.work);
-               }
+       /* The connection is still in hci_conn_hash so test for 1
+        * instead of 0 to know if this is the last one.
+        */
+       if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
+               cancel_delayed_work(&hdev->power_off);
+               queue_work(hdev->req_workqueue, &hdev->power_off.work);
        }
 
        if (!mgmt_connected)
@@ -6359,19 +6321,13 @@ void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
                         u8 addr_type, u8 status)
 {
        struct mgmt_ev_connect_failed ev;
-       struct pending_cmd *power_off;
-
-       power_off = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
-       if (power_off) {
-               struct mgmt_mode *cp = power_off->param;
 
-               /* The connection is still in hci_conn_hash so test for 1
-                * instead of 0 to know if this is the last one.
-                */
-               if (!cp->val && hci_conn_count(hdev) == 1) {
-                       cancel_delayed_work(&hdev->power_off);
-                       queue_work(hdev->req_workqueue, &hdev->power_off.work);
-               }
+       /* The connection is still in hci_conn_hash so test for 1
+        * instead of 0 to know if this is the last one.
+        */
+       if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
+               cancel_delayed_work(&hdev->power_off);
+               queue_work(hdev->req_workqueue, &hdev->power_off.work);
        }
 
        bacpy(&ev.addr.bdaddr, bdaddr);
index fd32943008030332bc523e12a8d2e9a560381f04..07ca4ce0943b5b3b6d976c7b2351343e20d83149 100644 (file)
@@ -44,7 +44,10 @@ enum {
 };
 
 struct smp_chan {
-       struct l2cap_conn *conn;
+       struct l2cap_conn       *conn;
+       struct delayed_work     security_timer;
+       struct work_struct      distribute_work;
+
        u8              preq[7]; /* SMP Pairing Request */
        u8              prsp[7]; /* SMP Pairing Response */
        u8              prnd[16]; /* SMP Pairing Random (local) */
@@ -139,12 +142,18 @@ static int smp_ah(struct crypto_blkcipher *tfm, u8 irk[16], u8 r[3], u8 res[3])
        return 0;
 }
 
-bool smp_irk_matches(struct crypto_blkcipher *tfm, u8 irk[16],
-                    bdaddr_t *bdaddr)
+bool smp_irk_matches(struct hci_dev *hdev, u8 irk[16], bdaddr_t *bdaddr)
 {
+       struct l2cap_chan *chan = hdev->smp_data;
+       struct crypto_blkcipher *tfm;
        u8 hash[3];
        int err;
 
+       if (!chan || !chan->data)
+               return false;
+
+       tfm = chan->data;
+
        BT_DBG("RPA %pMR IRK %*phN", bdaddr, 16, irk);
 
        err = smp_ah(tfm, irk, &bdaddr->b[3], hash);
@@ -154,10 +163,17 @@ bool smp_irk_matches(struct crypto_blkcipher *tfm, u8 irk[16],
        return !memcmp(bdaddr->b, hash, 3);
 }
 
-int smp_generate_rpa(struct crypto_blkcipher *tfm, u8 irk[16], bdaddr_t *rpa)
+int smp_generate_rpa(struct hci_dev *hdev, u8 irk[16], bdaddr_t *rpa)
 {
+       struct l2cap_chan *chan = hdev->smp_data;
+       struct crypto_blkcipher *tfm;
        int err;
 
+       if (!chan || !chan->data)
+               return -EOPNOTSUPP;
+
+       tfm = chan->data;
+
        get_random_bytes(&rpa->b[3], 3);
 
        rpa->b[5] &= 0x3f;      /* Clear two most significant bits */
@@ -235,47 +251,39 @@ static int smp_s1(struct smp_chan *smp, u8 k[16], u8 r1[16], u8 r2[16],
        return err;
 }
 
-static struct sk_buff *smp_build_cmd(struct l2cap_conn *conn, u8 code,
-                                    u16 dlen, void *data)
+static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)
 {
-       struct sk_buff *skb;
-       struct l2cap_hdr *lh;
-       int len;
-
-       len = L2CAP_HDR_SIZE + sizeof(code) + dlen;
-
-       if (len > conn->mtu)
-               return NULL;
+       struct l2cap_chan *chan = conn->smp;
+       struct smp_chan *smp;
+       struct kvec iv[2];
+       struct msghdr msg;
 
-       skb = bt_skb_alloc(len, GFP_ATOMIC);
-       if (!skb)
-               return NULL;
+       if (!chan)
+               return;
 
-       lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
-       lh->len = cpu_to_le16(sizeof(code) + dlen);
-       lh->cid = cpu_to_le16(L2CAP_CID_SMP);
+       BT_DBG("code 0x%2.2x", code);
 
-       memcpy(skb_put(skb, sizeof(code)), &code, sizeof(code));
+       iv[0].iov_base = &code;
+       iv[0].iov_len = 1;
 
-       memcpy(skb_put(skb, dlen), data, dlen);
+       iv[1].iov_base = data;
+       iv[1].iov_len = len;
 
-       return skb;
-}
+       memset(&msg, 0, sizeof(msg));
 
-static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)
-{
-       struct sk_buff *skb = smp_build_cmd(conn, code, len, data);
+       msg.msg_iov = (struct iovec *) &iv;
+       msg.msg_iovlen = 2;
 
-       BT_DBG("code 0x%2.2x", code);
+       l2cap_chan_send(chan, &msg, 1 + len);
 
-       if (!skb)
+       if (!chan->data)
                return;
 
-       skb->priority = HCI_PRIO_MAX;
-       hci_send_acl(conn->hchan, skb, 0);
+       smp = chan->data;
 
-       cancel_delayed_work_sync(&conn->security_timer);
-       schedule_delayed_work(&conn->security_timer, SMP_TIMEOUT);
+       cancel_delayed_work_sync(&smp->security_timer);
+       if (test_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags))
+               schedule_delayed_work(&smp->security_timer, SMP_TIMEOUT);
 }
 
 static __u8 authreq_to_seclevel(__u8 authreq)
@@ -302,7 +310,8 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
                              struct smp_cmd_pairing *req,
                              struct smp_cmd_pairing *rsp, __u8 authreq)
 {
-       struct smp_chan *smp = conn->smp_chan;
+       struct l2cap_chan *chan = conn->smp;
+       struct smp_chan *smp = chan->data;
        struct hci_conn *hcon = conn->hcon;
        struct hci_dev *hdev = hcon->hdev;
        u8 local_dist = 0, remote_dist = 0;
@@ -345,7 +354,8 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
 
 static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
 {
-       struct smp_chan *smp = conn->smp_chan;
+       struct l2cap_chan *chan = conn->smp;
+       struct smp_chan *smp = chan->data;
 
        if ((max_key_size > SMP_MAX_ENC_KEY_SIZE) ||
            (max_key_size < SMP_MIN_ENC_KEY_SIZE))
@@ -356,9 +366,61 @@ static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
        return 0;
 }
 
+static void smp_chan_destroy(struct l2cap_conn *conn)
+{
+       struct l2cap_chan *chan = conn->smp;
+       struct smp_chan *smp = chan->data;
+       bool complete;
+
+       BUG_ON(!smp);
+
+       cancel_delayed_work_sync(&smp->security_timer);
+       /* In case the timeout freed the SMP context */
+       if (!chan->data)
+               return;
+
+       if (work_pending(&smp->distribute_work)) {
+               cancel_work_sync(&smp->distribute_work);
+               if (!chan->data)
+                       return;
+       }
+
+       complete = test_bit(SMP_FLAG_COMPLETE, &smp->flags);
+       mgmt_smp_complete(conn->hcon, complete);
+
+       kfree(smp->csrk);
+       kfree(smp->slave_csrk);
+
+       crypto_free_blkcipher(smp->tfm_aes);
+
+       /* If pairing failed clean up any keys we might have */
+       if (!complete) {
+               if (smp->ltk) {
+                       list_del(&smp->ltk->list);
+                       kfree(smp->ltk);
+               }
+
+               if (smp->slave_ltk) {
+                       list_del(&smp->slave_ltk->list);
+                       kfree(smp->slave_ltk);
+               }
+
+               if (smp->remote_irk) {
+                       list_del(&smp->remote_irk->list);
+                       kfree(smp->remote_irk);
+               }
+       }
+
+       chan->data = NULL;
+       kfree(smp);
+       hci_conn_drop(conn->hcon);
+}
+
 static void smp_failure(struct l2cap_conn *conn, u8 reason)
 {
        struct hci_conn *hcon = conn->hcon;
+       struct l2cap_chan *chan = conn->smp;
+       struct smp_chan *smp;
 
        if (reason)
                smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason),
@@ -368,7 +430,10 @@ static void smp_failure(struct l2cap_conn *conn, u8 reason)
        mgmt_auth_failed(hcon->hdev, &hcon->dst, hcon->type, hcon->dst_type,
                         HCI_ERROR_AUTH_FAILURE);
 
-       cancel_delayed_work_sync(&conn->security_timer);
+       if (!chan->data)
+               return;
+
+       smp = chan->data;
 
        if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
                smp_chan_destroy(conn);
@@ -405,7 +470,8 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
                                                u8 local_io, u8 remote_io)
 {
        struct hci_conn *hcon = conn->hcon;
-       struct smp_chan *smp = conn->smp_chan;
+       struct l2cap_chan *chan = conn->smp;
+       struct smp_chan *smp = chan->data;
        u8 method;
        u32 passkey = 0;
        int ret = 0;
@@ -574,8 +640,201 @@ static u8 smp_random(struct smp_chan *smp)
        return 0;
 }
 
+static void smp_notify_keys(struct l2cap_conn *conn)
+{
+       struct l2cap_chan *chan = conn->smp;
+       struct smp_chan *smp = chan->data;
+       struct hci_conn *hcon = conn->hcon;
+       struct hci_dev *hdev = hcon->hdev;
+       struct smp_cmd_pairing *req = (void *) &smp->preq[1];
+       struct smp_cmd_pairing *rsp = (void *) &smp->prsp[1];
+       bool persistent;
+
+       if (smp->remote_irk) {
+               mgmt_new_irk(hdev, smp->remote_irk);
+               /* Now that user space can be considered to know the
+                * identity address track the connection based on it
+                * from now on.
+                */
+               bacpy(&hcon->dst, &smp->remote_irk->bdaddr);
+               hcon->dst_type = smp->remote_irk->addr_type;
+               l2cap_conn_update_id_addr(hcon);
+
+               /* When receiving an indentity resolving key for
+                * a remote device that does not use a resolvable
+                * private address, just remove the key so that
+                * it is possible to use the controller white
+                * list for scanning.
+                *
+                * Userspace will have been told to not store
+                * this key at this point. So it is safe to
+                * just remove it.
+                */
+               if (!bacmp(&smp->remote_irk->rpa, BDADDR_ANY)) {
+                       list_del(&smp->remote_irk->list);
+                       kfree(smp->remote_irk);
+                       smp->remote_irk = NULL;
+               }
+       }
+
+       /* The LTKs and CSRKs should be persistent only if both sides
+        * had the bonding bit set in their authentication requests.
+        */
+       persistent = !!((req->auth_req & rsp->auth_req) & SMP_AUTH_BONDING);
+
+       if (smp->csrk) {
+               smp->csrk->bdaddr_type = hcon->dst_type;
+               bacpy(&smp->csrk->bdaddr, &hcon->dst);
+               mgmt_new_csrk(hdev, smp->csrk, persistent);
+       }
+
+       if (smp->slave_csrk) {
+               smp->slave_csrk->bdaddr_type = hcon->dst_type;
+               bacpy(&smp->slave_csrk->bdaddr, &hcon->dst);
+               mgmt_new_csrk(hdev, smp->slave_csrk, persistent);
+       }
+
+       if (smp->ltk) {
+               smp->ltk->bdaddr_type = hcon->dst_type;
+               bacpy(&smp->ltk->bdaddr, &hcon->dst);
+               mgmt_new_ltk(hdev, smp->ltk, persistent);
+       }
+
+       if (smp->slave_ltk) {
+               smp->slave_ltk->bdaddr_type = hcon->dst_type;
+               bacpy(&smp->slave_ltk->bdaddr, &hcon->dst);
+               mgmt_new_ltk(hdev, smp->slave_ltk, persistent);
+       }
+}
+
+static void smp_distribute_keys(struct work_struct *work)
+{
+       struct smp_chan *smp = container_of(work, struct smp_chan,
+                                           distribute_work);
+       struct smp_cmd_pairing *req, *rsp;
+       struct l2cap_conn *conn = smp->conn;
+       struct hci_conn *hcon = conn->hcon;
+       struct hci_dev *hdev = hcon->hdev;
+       __u8 *keydist;
+
+       BT_DBG("conn %p", conn);
+
+       if (!test_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
+               return;
+
+       rsp = (void *) &smp->prsp[1];
+
+       /* The responder sends its keys first */
+       if (hcon->out && (smp->remote_key_dist & 0x07))
+               return;
+
+       req = (void *) &smp->preq[1];
+
+       if (hcon->out) {
+               keydist = &rsp->init_key_dist;
+               *keydist &= req->init_key_dist;
+       } else {
+               keydist = &rsp->resp_key_dist;
+               *keydist &= req->resp_key_dist;
+       }
+
+       BT_DBG("keydist 0x%x", *keydist);
+
+       if (*keydist & SMP_DIST_ENC_KEY) {
+               struct smp_cmd_encrypt_info enc;
+               struct smp_cmd_master_ident ident;
+               struct smp_ltk *ltk;
+               u8 authenticated;
+               __le16 ediv;
+               __le64 rand;
+
+               get_random_bytes(enc.ltk, sizeof(enc.ltk));
+               get_random_bytes(&ediv, sizeof(ediv));
+               get_random_bytes(&rand, sizeof(rand));
+
+               smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc);
+
+               authenticated = hcon->sec_level == BT_SECURITY_HIGH;
+               ltk = hci_add_ltk(hdev, &hcon->dst, hcon->dst_type,
+                                 SMP_LTK_SLAVE, authenticated, enc.ltk,
+                                 smp->enc_key_size, ediv, rand);
+               smp->slave_ltk = ltk;
+
+               ident.ediv = ediv;
+               ident.rand = rand;
+
+               smp_send_cmd(conn, SMP_CMD_MASTER_IDENT, sizeof(ident), &ident);
+
+               *keydist &= ~SMP_DIST_ENC_KEY;
+       }
+
+       if (*keydist & SMP_DIST_ID_KEY) {
+               struct smp_cmd_ident_addr_info addrinfo;
+               struct smp_cmd_ident_info idinfo;
+
+               memcpy(idinfo.irk, hdev->irk, sizeof(idinfo.irk));
+
+               smp_send_cmd(conn, SMP_CMD_IDENT_INFO, sizeof(idinfo), &idinfo);
+
+               /* The hci_conn contains the local identity address
+                * after the connection has been established.
+                *
+                * This is true even when the connection has been
+                * established using a resolvable random address.
+                */
+               bacpy(&addrinfo.bdaddr, &hcon->src);
+               addrinfo.addr_type = hcon->src_type;
+
+               smp_send_cmd(conn, SMP_CMD_IDENT_ADDR_INFO, sizeof(addrinfo),
+                            &addrinfo);
+
+               *keydist &= ~SMP_DIST_ID_KEY;
+       }
+
+       if (*keydist & SMP_DIST_SIGN) {
+               struct smp_cmd_sign_info sign;
+               struct smp_csrk *csrk;
+
+               /* Generate a new random key */
+               get_random_bytes(sign.csrk, sizeof(sign.csrk));
+
+               csrk = kzalloc(sizeof(*csrk), GFP_KERNEL);
+               if (csrk) {
+                       csrk->master = 0x00;
+                       memcpy(csrk->val, sign.csrk, sizeof(csrk->val));
+               }
+               smp->slave_csrk = csrk;
+
+               smp_send_cmd(conn, SMP_CMD_SIGN_INFO, sizeof(sign), &sign);
+
+               *keydist &= ~SMP_DIST_SIGN;
+       }
+
+       /* If there are still keys to be received wait for them */
+       if ((smp->remote_key_dist & 0x07))
+               return;
+
+       clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags);
+       set_bit(SMP_FLAG_COMPLETE, &smp->flags);
+       smp_notify_keys(conn);
+
+       smp_chan_destroy(conn);
+}
+
+static void smp_timeout(struct work_struct *work)
+{
+       struct smp_chan *smp = container_of(work, struct smp_chan,
+                                           security_timer.work);
+       struct l2cap_conn *conn = smp->conn;
+
+       BT_DBG("conn %p", conn);
+
+       l2cap_conn_shutdown(conn, ETIMEDOUT);
+}
+
 static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
 {
+       struct l2cap_chan *chan = conn->smp;
        struct smp_chan *smp;
 
        smp = kzalloc(sizeof(*smp), GFP_ATOMIC);
@@ -593,54 +852,20 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
        }
 
        smp->conn = conn;
-       conn->smp_chan = smp;
+       chan->data = smp;
+
+       INIT_WORK(&smp->distribute_work, smp_distribute_keys);
+       INIT_DELAYED_WORK(&smp->security_timer, smp_timeout);
 
        hci_conn_hold(conn->hcon);
 
        return smp;
 }
 
-void smp_chan_destroy(struct l2cap_conn *conn)
-{
-       struct smp_chan *smp = conn->smp_chan;
-       bool complete;
-
-       BUG_ON(!smp);
-
-       complete = test_bit(SMP_FLAG_COMPLETE, &smp->flags);
-       mgmt_smp_complete(conn->hcon, complete);
-
-       kfree(smp->csrk);
-       kfree(smp->slave_csrk);
-
-       crypto_free_blkcipher(smp->tfm_aes);
-
-       /* If pairing failed clean up any keys we might have */
-       if (!complete) {
-               if (smp->ltk) {
-                       list_del(&smp->ltk->list);
-                       kfree(smp->ltk);
-               }
-
-               if (smp->slave_ltk) {
-                       list_del(&smp->slave_ltk->list);
-                       kfree(smp->slave_ltk);
-               }
-
-               if (smp->remote_irk) {
-                       list_del(&smp->remote_irk->list);
-                       kfree(smp->remote_irk);
-               }
-       }
-
-       kfree(smp);
-       conn->smp_chan = NULL;
-       hci_conn_drop(conn->hcon);
-}
-
 int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey)
 {
        struct l2cap_conn *conn = hcon->l2cap_data;
+       struct l2cap_chan *chan;
        struct smp_chan *smp;
        u32 value;
 
@@ -649,7 +874,11 @@ int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey)
        if (!conn || !test_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
                return -ENOTCONN;
 
-       smp = conn->smp_chan;
+       chan = conn->smp;
+       if (!chan)
+               return -ENOTCONN;
+
+       smp = chan->data;
 
        switch (mgmt_op) {
        case MGMT_OP_USER_PASSKEY_REPLY:
@@ -696,10 +925,12 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
        if (conn->hcon->role != HCI_ROLE_SLAVE)
                return SMP_CMD_NOTSUPP;
 
-       if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags))
+       if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) {
                smp = smp_chan_create(conn);
-       else
-               smp = conn->smp_chan;
+       } else {
+               struct l2cap_chan *chan = conn->smp;
+               smp = chan->data;
+       }
 
        if (!smp)
                return SMP_UNSPECIFIED;
@@ -753,7 +984,8 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
 static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
 {
        struct smp_cmd_pairing *req, *rsp = (void *) skb->data;
-       struct smp_chan *smp = conn->smp_chan;
+       struct l2cap_chan *chan = conn->smp;
+       struct smp_chan *smp = chan->data;
        u8 key_size, auth = SMP_AUTH_NONE;
        int ret;
 
@@ -814,7 +1046,8 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
 
 static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
 {
-       struct smp_chan *smp = conn->smp_chan;
+       struct l2cap_chan *chan = conn->smp;
+       struct smp_chan *smp = chan->data;
 
        BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
 
@@ -837,7 +1070,8 @@ static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
 
 static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
 {
-       struct smp_chan *smp = conn->smp_chan;
+       struct l2cap_chan *chan = conn->smp;
+       struct smp_chan *smp = chan->data;
 
        BT_DBG("conn %p", conn);
 
@@ -1010,7 +1244,8 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
 static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb)
 {
        struct smp_cmd_encrypt_info *rp = (void *) skb->data;
-       struct smp_chan *smp = conn->smp_chan;
+       struct l2cap_chan *chan = conn->smp;
+       struct smp_chan *smp = chan->data;
 
        BT_DBG("conn %p", conn);
 
@@ -1031,7 +1266,8 @@ static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb)
 static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
 {
        struct smp_cmd_master_ident *rp = (void *) skb->data;
-       struct smp_chan *smp = conn->smp_chan;
+       struct l2cap_chan *chan = conn->smp;
+       struct smp_chan *smp = chan->data;
        struct hci_dev *hdev = conn->hcon->hdev;
        struct hci_conn *hcon = conn->hcon;
        struct smp_ltk *ltk;
@@ -1058,7 +1294,7 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
                          rp->ediv, rp->rand);
        smp->ltk = ltk;
        if (!(smp->remote_key_dist & SMP_DIST_ID_KEY))
-               smp_distribute_keys(conn);
+               queue_work(hdev->workqueue, &smp->distribute_work);
        hci_dev_unlock(hdev);
 
        return 0;
@@ -1067,7 +1303,8 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
 static int smp_cmd_ident_info(struct l2cap_conn *conn, struct sk_buff *skb)
 {
        struct smp_cmd_ident_info *info = (void *) skb->data;
-       struct smp_chan *smp = conn->smp_chan;
+       struct l2cap_chan *chan = conn->smp;
+       struct smp_chan *smp = chan->data;
 
        BT_DBG("");
 
@@ -1089,8 +1326,10 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn,
                                   struct sk_buff *skb)
 {
        struct smp_cmd_ident_addr_info *info = (void *) skb->data;
-       struct smp_chan *smp = conn->smp_chan;
+       struct l2cap_chan *chan = conn->smp;
+       struct smp_chan *smp = chan->data;
        struct hci_conn *hcon = conn->hcon;
+       struct hci_dev *hdev = hcon->hdev;
        bdaddr_t rpa;
 
        BT_DBG("");
@@ -1133,7 +1372,7 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn,
                                      smp->id_addr_type, smp->irk, &rpa);
 
 distribute:
-       smp_distribute_keys(conn);
+       queue_work(hdev->workqueue, &smp->distribute_work);
 
        hci_dev_unlock(hcon->hdev);
 
@@ -1143,7 +1382,8 @@ distribute:
 static int smp_cmd_sign_info(struct l2cap_conn *conn, struct sk_buff *skb)
 {
        struct smp_cmd_sign_info *rp = (void *) skb->data;
-       struct smp_chan *smp = conn->smp_chan;
+       struct l2cap_chan *chan = conn->smp;
+       struct smp_chan *smp = chan->data;
        struct hci_dev *hdev = conn->hcon->hdev;
        struct smp_csrk *csrk;
 
@@ -1168,15 +1408,15 @@ static int smp_cmd_sign_info(struct l2cap_conn *conn, struct sk_buff *skb)
                memcpy(csrk->val, rp->csrk, sizeof(csrk->val));
        }
        smp->csrk = csrk;
-       if (!(smp->remote_key_dist & SMP_DIST_SIGN))
-               smp_distribute_keys(conn);
+       queue_work(hdev->workqueue, &smp->distribute_work);
        hci_dev_unlock(hdev);
 
        return 0;
 }
 
-int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
+static int smp_sig_channel(struct l2cap_chan *chan, struct sk_buff *skb)
 {
+       struct l2cap_conn *conn = chan->conn;
        struct hci_conn *hcon = conn->hcon;
        __u8 code, reason;
        int err = 0;
@@ -1186,10 +1426,8 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
                return 0;
        }
 
-       if (skb->len < 1) {
-               kfree_skb(skb);
+       if (skb->len < 1)
                return -EILSEQ;
-       }
 
        if (!test_bit(HCI_LE_ENABLED, &hcon->hdev->dev_flags)) {
                err = -EOPNOTSUPP;
@@ -1207,10 +1445,11 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
         * returns an error).
         */
        if (code != SMP_CMD_PAIRING_REQ && code != SMP_CMD_SECURITY_REQ &&
-           !conn->smp_chan) {
+           !test_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) {
                BT_ERR("Unexpected SMP command 0x%02x. Disconnecting.", code);
-               kfree_skb(skb);
-               return -EOPNOTSUPP;
+               reason = SMP_CMD_NOTSUPP;
+               err = -EOPNOTSUPP;
+               goto done;
        }
 
        switch (code) {
@@ -1271,188 +1510,201 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
 done:
        if (reason)
                smp_failure(conn, reason);
-
-       kfree_skb(skb);
+       if (!err)
+               kfree_skb(skb);
        return err;
 }
 
-static void smp_notify_keys(struct l2cap_conn *conn)
+static void smp_teardown_cb(struct l2cap_chan *chan, int err)
 {
-       struct smp_chan *smp = conn->smp_chan;
+       struct l2cap_conn *conn = chan->conn;
+
+       BT_DBG("chan %p", chan);
+
+       if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags))
+               smp_chan_destroy(conn);
+
+       conn->smp = NULL;
+       l2cap_chan_put(chan);
+}
+
+static void smp_resume_cb(struct l2cap_chan *chan)
+{
+       struct smp_chan *smp = chan->data;
+       struct l2cap_conn *conn = chan->conn;
        struct hci_conn *hcon = conn->hcon;
        struct hci_dev *hdev = hcon->hdev;
-       struct smp_cmd_pairing *req = (void *) &smp->preq[1];
-       struct smp_cmd_pairing *rsp = (void *) &smp->prsp[1];
-       bool persistent;
 
-       if (smp->remote_irk) {
-               mgmt_new_irk(hdev, smp->remote_irk);
-               /* Now that user space can be considered to know the
-                * identity address track the connection based on it
-                * from now on.
-                */
-               bacpy(&hcon->dst, &smp->remote_irk->bdaddr);
-               hcon->dst_type = smp->remote_irk->addr_type;
-               l2cap_conn_update_id_addr(hcon);
+       BT_DBG("chan %p", chan);
 
-               /* When receiving an indentity resolving key for
-                * a remote device that does not use a resolvable
-                * private address, just remove the key so that
-                * it is possible to use the controller white
-                * list for scanning.
-                *
-                * Userspace will have been told to not store
-                * this key at this point. So it is safe to
-                * just remove it.
-                */
-               if (!bacmp(&smp->remote_irk->rpa, BDADDR_ANY)) {
-                       list_del(&smp->remote_irk->list);
-                       kfree(smp->remote_irk);
-                       smp->remote_irk = NULL;
-               }
-       }
+       if (!smp)
+               return;
 
-       /* The LTKs and CSRKs should be persistent only if both sides
-        * had the bonding bit set in their authentication requests.
-        */
-       persistent = !!((req->auth_req & rsp->auth_req) & SMP_AUTH_BONDING);
+       cancel_delayed_work(&smp->security_timer);
 
-       if (smp->csrk) {
-               smp->csrk->bdaddr_type = hcon->dst_type;
-               bacpy(&smp->csrk->bdaddr, &hcon->dst);
-               mgmt_new_csrk(hdev, smp->csrk, persistent);
-       }
+       if (test_bit(HCI_CONN_ENCRYPT, &hcon->flags))
+               queue_work(hdev->workqueue, &smp->distribute_work);
+}
 
-       if (smp->slave_csrk) {
-               smp->slave_csrk->bdaddr_type = hcon->dst_type;
-               bacpy(&smp->slave_csrk->bdaddr, &hcon->dst);
-               mgmt_new_csrk(hdev, smp->slave_csrk, persistent);
-       }
+static void smp_ready_cb(struct l2cap_chan *chan)
+{
+       struct l2cap_conn *conn = chan->conn;
 
-       if (smp->ltk) {
-               smp->ltk->bdaddr_type = hcon->dst_type;
-               bacpy(&smp->ltk->bdaddr, &hcon->dst);
-               mgmt_new_ltk(hdev, smp->ltk, persistent);
-       }
+       BT_DBG("chan %p", chan);
 
-       if (smp->slave_ltk) {
-               smp->slave_ltk->bdaddr_type = hcon->dst_type;
-               bacpy(&smp->slave_ltk->bdaddr, &hcon->dst);
-               mgmt_new_ltk(hdev, smp->slave_ltk, persistent);
-       }
+       conn->smp = chan;
+       l2cap_chan_hold(chan);
 }
 
-int smp_distribute_keys(struct l2cap_conn *conn)
+static int smp_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
 {
-       struct smp_cmd_pairing *req, *rsp;
-       struct smp_chan *smp = conn->smp_chan;
-       struct hci_conn *hcon = conn->hcon;
-       struct hci_dev *hdev = hcon->hdev;
-       __u8 *keydist;
+       int err;
 
-       BT_DBG("conn %p", conn);
+       BT_DBG("chan %p", chan);
 
-       if (!test_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
-               return 0;
+       err = smp_sig_channel(chan, skb);
+       if (err) {
+               struct smp_chan *smp = chan->data;
 
-       rsp = (void *) &smp->prsp[1];
+               if (smp)
+                       cancel_delayed_work_sync(&smp->security_timer);
 
-       /* The responder sends its keys first */
-       if (hcon->out && (smp->remote_key_dist & 0x07))
-               return 0;
+               l2cap_conn_shutdown(chan->conn, -err);
+       }
 
-       req = (void *) &smp->preq[1];
+       return err;
+}
 
-       if (hcon->out) {
-               keydist = &rsp->init_key_dist;
-               *keydist &= req->init_key_dist;
-       } else {
-               keydist = &rsp->resp_key_dist;
-               *keydist &= req->resp_key_dist;
-       }
+static struct sk_buff *smp_alloc_skb_cb(struct l2cap_chan *chan,
+                                       unsigned long hdr_len,
+                                       unsigned long len, int nb)
+{
+       struct sk_buff *skb;
 
-       BT_DBG("keydist 0x%x", *keydist);
+       skb = bt_skb_alloc(hdr_len + len, GFP_KERNEL);
+       if (!skb)
+               return ERR_PTR(-ENOMEM);
 
-       if (*keydist & SMP_DIST_ENC_KEY) {
-               struct smp_cmd_encrypt_info enc;
-               struct smp_cmd_master_ident ident;
-               struct smp_ltk *ltk;
-               u8 authenticated;
-               __le16 ediv;
-               __le64 rand;
+       skb->priority = HCI_PRIO_MAX;
+       bt_cb(skb)->chan = chan;
 
-               get_random_bytes(enc.ltk, sizeof(enc.ltk));
-               get_random_bytes(&ediv, sizeof(ediv));
-               get_random_bytes(&rand, sizeof(rand));
+       return skb;
+}
 
-               smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc);
+static const struct l2cap_ops smp_chan_ops = {
+       .name                   = "Security Manager",
+       .ready                  = smp_ready_cb,
+       .recv                   = smp_recv_cb,
+       .alloc_skb              = smp_alloc_skb_cb,
+       .teardown               = smp_teardown_cb,
+       .resume                 = smp_resume_cb,
+
+       .new_connection         = l2cap_chan_no_new_connection,
+       .state_change           = l2cap_chan_no_state_change,
+       .close                  = l2cap_chan_no_close,
+       .defer                  = l2cap_chan_no_defer,
+       .suspend                = l2cap_chan_no_suspend,
+       .set_shutdown           = l2cap_chan_no_set_shutdown,
+       .get_sndtimeo           = l2cap_chan_no_get_sndtimeo,
+       .memcpy_fromiovec       = l2cap_chan_no_memcpy_fromiovec,
+};
 
-               authenticated = hcon->sec_level == BT_SECURITY_HIGH;
-               ltk = hci_add_ltk(hdev, &hcon->dst, hcon->dst_type,
-                                 SMP_LTK_SLAVE, authenticated, enc.ltk,
-                                 smp->enc_key_size, ediv, rand);
-               smp->slave_ltk = ltk;
+static inline struct l2cap_chan *smp_new_conn_cb(struct l2cap_chan *pchan)
+{
+       struct l2cap_chan *chan;
 
-               ident.ediv = ediv;
-               ident.rand = rand;
+       BT_DBG("pchan %p", pchan);
 
-               smp_send_cmd(conn, SMP_CMD_MASTER_IDENT, sizeof(ident), &ident);
+       chan = l2cap_chan_create();
+       if (!chan)
+               return NULL;
 
-               *keydist &= ~SMP_DIST_ENC_KEY;
-       }
+       chan->chan_type = pchan->chan_type;
+       chan->ops       = &smp_chan_ops;
+       chan->scid      = pchan->scid;
+       chan->dcid      = chan->scid;
+       chan->imtu      = pchan->imtu;
+       chan->omtu      = pchan->omtu;
+       chan->mode      = pchan->mode;
 
-       if (*keydist & SMP_DIST_ID_KEY) {
-               struct smp_cmd_ident_addr_info addrinfo;
-               struct smp_cmd_ident_info idinfo;
+       BT_DBG("created chan %p", chan);
 
-               memcpy(idinfo.irk, hdev->irk, sizeof(idinfo.irk));
+       return chan;
+}
 
-               smp_send_cmd(conn, SMP_CMD_IDENT_INFO, sizeof(idinfo), &idinfo);
+static const struct l2cap_ops smp_root_chan_ops = {
+       .name                   = "Security Manager Root",
+       .new_connection         = smp_new_conn_cb,
+
+       /* None of these are implemented for the root channel */
+       .close                  = l2cap_chan_no_close,
+       .alloc_skb              = l2cap_chan_no_alloc_skb,
+       .recv                   = l2cap_chan_no_recv,
+       .state_change           = l2cap_chan_no_state_change,
+       .teardown               = l2cap_chan_no_teardown,
+       .ready                  = l2cap_chan_no_ready,
+       .defer                  = l2cap_chan_no_defer,
+       .suspend                = l2cap_chan_no_suspend,
+       .resume                 = l2cap_chan_no_resume,
+       .set_shutdown           = l2cap_chan_no_set_shutdown,
+       .get_sndtimeo           = l2cap_chan_no_get_sndtimeo,
+       .memcpy_fromiovec       = l2cap_chan_no_memcpy_fromiovec,
+};
 
-               /* The hci_conn contains the local identity address
-                * after the connection has been established.
-                *
-                * This is true even when the connection has been
-                * established using a resolvable random address.
-                */
-               bacpy(&addrinfo.bdaddr, &hcon->src);
-               addrinfo.addr_type = hcon->src_type;
+int smp_register(struct hci_dev *hdev)
+{
+       struct l2cap_chan *chan;
+       struct crypto_blkcipher *tfm_aes;
 
-               smp_send_cmd(conn, SMP_CMD_IDENT_ADDR_INFO, sizeof(addrinfo),
-                            &addrinfo);
+       BT_DBG("%s", hdev->name);
 
-               *keydist &= ~SMP_DIST_ID_KEY;
+       tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC);
+       if (IS_ERR(tfm_aes)) {
+               int err = PTR_ERR(tfm_aes);
+               BT_ERR("Unable to create crypto context");
+               return err;
        }
 
-       if (*keydist & SMP_DIST_SIGN) {
-               struct smp_cmd_sign_info sign;
-               struct smp_csrk *csrk;
+       chan = l2cap_chan_create();
+       if (!chan) {
+               crypto_free_blkcipher(tfm_aes);
+               return -ENOMEM;
+       }
 
-               /* Generate a new random key */
-               get_random_bytes(sign.csrk, sizeof(sign.csrk));
+       chan->data = tfm_aes;
 
-               csrk = kzalloc(sizeof(*csrk), GFP_KERNEL);
-               if (csrk) {
-                       csrk->master = 0x00;
-                       memcpy(csrk->val, sign.csrk, sizeof(csrk->val));
-               }
-               smp->slave_csrk = csrk;
+       l2cap_add_scid(chan, L2CAP_CID_SMP);
 
-               smp_send_cmd(conn, SMP_CMD_SIGN_INFO, sizeof(sign), &sign);
+       l2cap_chan_set_defaults(chan);
 
-               *keydist &= ~SMP_DIST_SIGN;
-       }
+       bacpy(&chan->src, &hdev->bdaddr);
+       chan->src_type = BDADDR_LE_PUBLIC;
+       chan->state = BT_LISTEN;
+       chan->mode = L2CAP_MODE_BASIC;
+       chan->imtu = L2CAP_DEFAULT_MTU;
+       chan->ops = &smp_root_chan_ops;
 
-       /* If there are still keys to be received wait for them */
-       if ((smp->remote_key_dist & 0x07))
-               return 0;
+       hdev->smp_data = chan;
 
-       clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags);
-       cancel_delayed_work_sync(&conn->security_timer);
-       set_bit(SMP_FLAG_COMPLETE, &smp->flags);
-       smp_notify_keys(conn);
+       return 0;
+}
 
-       smp_chan_destroy(conn);
+void smp_unregister(struct hci_dev *hdev)
+{
+       struct l2cap_chan *chan = hdev->smp_data;
+       struct crypto_blkcipher *tfm_aes;
 
-       return 0;
+       if (!chan)
+               return;
+
+       BT_DBG("%s chan %p", hdev->name, chan);
+
+       tfm_aes = chan->data;
+       if (tfm_aes) {
+               chan->data = NULL;
+               crypto_free_blkcipher(tfm_aes);
+       }
+
+       hdev->smp_data = NULL;
+       l2cap_chan_put(chan);
 }
index 796f4f45f92f67e43e32d75bfb015b5175f2aba0..cf1094617c69890eb489d314cc2b7ce021305673 100644 (file)
@@ -126,14 +126,12 @@ enum {
 /* SMP Commands */
 bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level);
 int smp_conn_security(struct hci_conn *hcon, __u8 sec_level);
-int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb);
-int smp_distribute_keys(struct l2cap_conn *conn);
 int smp_user_confirm_reply(struct hci_conn *conn, u16 mgmt_op, __le32 passkey);
 
-void smp_chan_destroy(struct l2cap_conn *conn);
+bool smp_irk_matches(struct hci_dev *hdev, u8 irk[16], bdaddr_t *bdaddr);
+int smp_generate_rpa(struct hci_dev *hdev, u8 irk[16], bdaddr_t *rpa);
 
-bool smp_irk_matches(struct crypto_blkcipher *tfm, u8 irk[16],
-                    bdaddr_t *bdaddr);
-int smp_generate_rpa(struct crypto_blkcipher *tfm, u8 irk[16], bdaddr_t *rpa);
+int smp_register(struct hci_dev *hdev);
+void smp_unregister(struct hci_dev *hdev);
 
 #endif /* __SMP_H */
index 078d336a1f379f80d622e4fffa187630593827cf..a9f54a9b6690b181090fd15be8bf8e78c241fac4 100644 (file)
@@ -252,12 +252,12 @@ static void del_nbp(struct net_bridge_port *p)
        br_fdb_delete_by_port(br, p, 1);
        nbp_update_port_count(br);
 
+       netdev_upper_dev_unlink(dev, br->dev);
+
        dev->priv_flags &= ~IFF_BRIDGE_PORT;
 
        netdev_rx_handler_unregister(dev);
 
-       netdev_upper_dev_unlink(dev, br->dev);
-
        br_multicast_del_port(p);
 
        kobject_uevent(&p->kobj, KOBJ_REMOVE);
@@ -476,16 +476,16 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
        if (err)
                goto err3;
 
-       err = netdev_master_upper_dev_link(dev, br->dev);
+       err = netdev_rx_handler_register(dev, br_handle_frame, p);
        if (err)
                goto err4;
 
-       err = netdev_rx_handler_register(dev, br_handle_frame, p);
+       dev->priv_flags |= IFF_BRIDGE_PORT;
+
+       err = netdev_master_upper_dev_link(dev, br->dev);
        if (err)
                goto err5;
 
-       dev->priv_flags |= IFF_BRIDGE_PORT;
-
        dev_disable_lro(dev);
 
        list_add_rcu(&p->list, &br->port_list);
@@ -520,7 +520,8 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
        return 0;
 
 err5:
-       netdev_upper_dev_unlink(dev, br->dev);
+       dev->priv_flags &= ~IFF_BRIDGE_PORT;
+       netdev_rx_handler_unregister(dev);
 err4:
        br_netpoll_disable(p);
 err3:
index 7751c92c8c57fc24b0c18e4d20a095bfa02e9ff0..648d79ccf46244a5769c1703361cf35db4cfeb09 100644 (file)
@@ -1822,7 +1822,7 @@ static void br_multicast_query_expired(struct net_bridge *br,
        if (query->startup_sent < br->multicast_startup_query_count)
                query->startup_sent++;
 
-       rcu_assign_pointer(querier, NULL);
+       RCU_INIT_POINTER(querier, NULL);
        br_multicast_send_query(br, NULL, query);
        spin_unlock(&br->multicast_lock);
 }
index cb5fcf62f66332d2ef9fb3f46260d43583713a1d..90a91e137acc3112004a4108abb68371919fa2be 100644 (file)
@@ -257,9 +257,6 @@ static int br_afspec(struct net_bridge *br,
                        } else
                                err = br_vlan_add(br, vinfo->vid, vinfo->flags);
 
-                       if (err)
-                               break;
-
                        break;
 
                case RTM_DELLINK:
@@ -276,7 +273,7 @@ static int br_afspec(struct net_bridge *br,
        return err;
 }
 
-static const struct nla_policy ifla_brport_policy[IFLA_BRPORT_MAX + 1] = {
+static const struct nla_policy br_port_policy[IFLA_BRPORT_MAX + 1] = {
        [IFLA_BRPORT_STATE]     = { .type = NLA_U8 },
        [IFLA_BRPORT_COST]      = { .type = NLA_U32 },
        [IFLA_BRPORT_PRIORITY]  = { .type = NLA_U16 },
@@ -382,7 +379,7 @@ int br_setlink(struct net_device *dev, struct nlmsghdr *nlh)
        if (p && protinfo) {
                if (protinfo->nla_type & NLA_F_NESTED) {
                        err = nla_parse_nested(tb, IFLA_BRPORT_MAX,
-                                              protinfo, ifla_brport_policy);
+                                              protinfo, br_port_policy);
                        if (err)
                                return err;
 
@@ -461,6 +458,88 @@ static int br_dev_newlink(struct net *src_net, struct net_device *dev,
        return register_netdevice(dev);
 }
 
+static int br_port_slave_changelink(struct net_device *brdev,
+                                   struct net_device *dev,
+                                   struct nlattr *tb[],
+                                   struct nlattr *data[])
+{
+       if (!data)
+               return 0;
+       return br_setport(br_port_get_rtnl(dev), data);
+}
+
+static int br_port_fill_slave_info(struct sk_buff *skb,
+                                  const struct net_device *brdev,
+                                  const struct net_device *dev)
+{
+       return br_port_fill_attrs(skb, br_port_get_rtnl(dev));
+}
+
+static size_t br_port_get_slave_size(const struct net_device *brdev,
+                                    const struct net_device *dev)
+{
+       return br_port_info_size();
+}
+
+static const struct nla_policy br_policy[IFLA_BR_MAX + 1] = {
+       [IFLA_BR_FORWARD_DELAY] = { .type = NLA_U32 },
+       [IFLA_BR_HELLO_TIME]    = { .type = NLA_U32 },
+       [IFLA_BR_MAX_AGE]       = { .type = NLA_U32 },
+};
+
+static int br_changelink(struct net_device *brdev, struct nlattr *tb[],
+                        struct nlattr *data[])
+{
+       struct net_bridge *br = netdev_priv(brdev);
+       int err;
+
+       if (!data)
+               return 0;
+
+       if (data[IFLA_BR_FORWARD_DELAY]) {
+               err = br_set_forward_delay(br, nla_get_u32(data[IFLA_BR_FORWARD_DELAY]));
+               if (err)
+                       return err;
+       }
+
+       if (data[IFLA_BR_HELLO_TIME]) {
+               err = br_set_hello_time(br, nla_get_u32(data[IFLA_BR_HELLO_TIME]));
+               if (err)
+                       return err;
+       }
+
+       if (data[IFLA_BR_MAX_AGE]) {
+               err = br_set_max_age(br, nla_get_u32(data[IFLA_BR_MAX_AGE]));
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
+static size_t br_get_size(const struct net_device *brdev)
+{
+       return nla_total_size(sizeof(u32)) +    /* IFLA_BR_FORWARD_DELAY  */
+              nla_total_size(sizeof(u32)) +    /* IFLA_BR_HELLO_TIME */
+              nla_total_size(sizeof(u32)) +    /* IFLA_BR_MAX_AGE */
+              0;
+}
+
+static int br_fill_info(struct sk_buff *skb, const struct net_device *brdev)
+{
+       struct net_bridge *br = netdev_priv(brdev);
+       u32 forward_delay = jiffies_to_clock_t(br->forward_delay);
+       u32 hello_time = jiffies_to_clock_t(br->hello_time);
+       u32 age_time = jiffies_to_clock_t(br->max_age);
+
+       if (nla_put_u32(skb, IFLA_BR_FORWARD_DELAY, forward_delay) ||
+           nla_put_u32(skb, IFLA_BR_HELLO_TIME, hello_time) ||
+           nla_put_u32(skb, IFLA_BR_MAX_AGE, age_time))
+               return -EMSGSIZE;
+
+       return 0;
+}
+
 static size_t br_get_link_af_size(const struct net_device *dev)
 {
        struct net_port_vlans *pv;
@@ -485,12 +564,23 @@ static struct rtnl_af_ops br_af_ops = {
 };
 
 struct rtnl_link_ops br_link_ops __read_mostly = {
-       .kind           = "bridge",
-       .priv_size      = sizeof(struct net_bridge),
-       .setup          = br_dev_setup,
-       .validate       = br_validate,
-       .newlink        = br_dev_newlink,
-       .dellink        = br_dev_delete,
+       .kind                   = "bridge",
+       .priv_size              = sizeof(struct net_bridge),
+       .setup                  = br_dev_setup,
+       .maxtype                = IFLA_BRPORT_MAX,
+       .policy                 = br_policy,
+       .validate               = br_validate,
+       .newlink                = br_dev_newlink,
+       .changelink             = br_changelink,
+       .dellink                = br_dev_delete,
+       .get_size               = br_get_size,
+       .fill_info              = br_fill_info,
+
+       .slave_maxtype          = IFLA_BRPORT_MAX,
+       .slave_policy           = br_port_policy,
+       .slave_changelink       = br_port_slave_changelink,
+       .get_slave_size         = br_port_get_slave_size,
+       .fill_slave_info        = br_port_fill_slave_info,
 };
 
 int __init br_netlink_init(void)
index 488dd1a825c05b704a26d8c88582454f1745be4c..fdbc9a81d4c2033565c36815d425d0a7d80372b7 100644 (file)
@@ -775,7 +775,7 @@ __sum16 __skb_checksum_complete(struct sk_buff *skb)
 EXPORT_SYMBOL(__skb_checksum_complete);
 
 /**
- *     skb_copy_and_csum_datagram_iovec - Copy and checkum skb to user iovec.
+ *     skb_copy_and_csum_datagram_iovec - Copy and checksum skb to user iovec.
  *     @skb: skbuff
  *     @hlen: hardware length
  *     @iov: io vector
index b65a5051361f2dea31a0fac078b3dd656e126cc8..3c6a967e583070f35f3b8c173c7314ac5030a0a3 100644 (file)
@@ -2485,52 +2485,6 @@ static int illegal_highdma(struct net_device *dev, struct sk_buff *skb)
        return 0;
 }
 
-struct dev_gso_cb {
-       void (*destructor)(struct sk_buff *skb);
-};
-
-#define DEV_GSO_CB(skb) ((struct dev_gso_cb *)(skb)->cb)
-
-static void dev_gso_skb_destructor(struct sk_buff *skb)
-{
-       struct dev_gso_cb *cb;
-
-       kfree_skb_list(skb->next);
-       skb->next = NULL;
-
-       cb = DEV_GSO_CB(skb);
-       if (cb->destructor)
-               cb->destructor(skb);
-}
-
-/**
- *     dev_gso_segment - Perform emulated hardware segmentation on skb.
- *     @skb: buffer to segment
- *     @features: device features as applicable to this skb
- *
- *     This function segments the given skb and stores the list of segments
- *     in skb->next.
- */
-static int dev_gso_segment(struct sk_buff *skb, netdev_features_t features)
-{
-       struct sk_buff *segs;
-
-       segs = skb_gso_segment(skb, features);
-
-       /* Verifying header integrity only. */
-       if (!segs)
-               return 0;
-
-       if (IS_ERR(segs))
-               return PTR_ERR(segs);
-
-       skb->next = segs;
-       DEV_GSO_CB(skb)->destructor = skb->destructor;
-       skb->destructor = dev_gso_skb_destructor;
-
-       return 0;
-}
-
 /* If MPLS offload request, verify we are testing hardware MPLS features
  * instead of standard features for the netdev.
  */
@@ -2587,131 +2541,143 @@ netdev_features_t netif_skb_features(struct sk_buff *skb)
                return harmonize_features(skb, features);
        }
 
-       features &= (skb->dev->vlan_features | NETIF_F_HW_VLAN_CTAG_TX |
-                                              NETIF_F_HW_VLAN_STAG_TX);
+       features = netdev_intersect_features(features,
+                                            skb->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))
-               features &= NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST |
-                               NETIF_F_GEN_CSUM | NETIF_F_HW_VLAN_CTAG_TX |
-                               NETIF_F_HW_VLAN_STAG_TX;
+               features = netdev_intersect_features(features,
+                                                    NETIF_F_SG |
+                                                    NETIF_F_HIGHDMA |
+                                                    NETIF_F_FRAGLIST |
+                                                    NETIF_F_GEN_CSUM |
+                                                    NETIF_F_HW_VLAN_CTAG_TX |
+                                                    NETIF_F_HW_VLAN_STAG_TX);
 
        return harmonize_features(skb, features);
 }
 EXPORT_SYMBOL(netif_skb_features);
 
-int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
-                       struct netdev_queue *txq)
+static int xmit_one(struct sk_buff *skb, struct net_device *dev,
+                   struct netdev_queue *txq, bool more)
 {
-       const struct net_device_ops *ops = dev->netdev_ops;
+       unsigned int len;
+       int rc;
+
+       if (!list_empty(&ptype_all))
+               dev_queue_xmit_nit(skb, dev);
+
+       len = skb->len;
+       trace_net_dev_start_xmit(skb, dev);
+       rc = netdev_start_xmit(skb, dev, txq, more);
+       trace_net_dev_xmit(skb, rc, dev, len);
+
+       return rc;
+}
+
+struct sk_buff *dev_hard_start_xmit(struct sk_buff *first, struct net_device *dev,
+                                   struct netdev_queue *txq, int *ret)
+{
+       struct sk_buff *skb = first;
        int rc = NETDEV_TX_OK;
-       unsigned int skb_len;
 
-       if (likely(!skb->next)) {
-               netdev_features_t features;
+       while (skb) {
+               struct sk_buff *next = skb->next;
 
-               /*
-                * If device doesn't need skb->dst, release it right now while
-                * its hot in this cpu cache
-                */
-               if (dev->priv_flags & IFF_XMIT_DST_RELEASE)
-                       skb_dst_drop(skb);
+               skb->next = NULL;
+               rc = xmit_one(skb, dev, txq, next != NULL);
+               if (unlikely(!dev_xmit_complete(rc))) {
+                       skb->next = next;
+                       goto out;
+               }
 
-               features = netif_skb_features(skb);
+               skb = next;
+               if (netif_xmit_stopped(txq) && skb) {
+                       rc = NETDEV_TX_BUSY;
+                       break;
+               }
+       }
 
-               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))
-                               goto out;
+out:
+       *ret = rc;
+       return skb;
+}
 
+struct sk_buff *validate_xmit_vlan(struct sk_buff *skb, netdev_features_t features)
+{
+       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 (skb)
                        skb->vlan_tci = 0;
-               }
+       }
+       return skb;
+}
 
-               /* If encapsulation offload request, verify we are testing
-                * hardware encapsulation features instead of standard
-                * features for the netdev
-                */
-               if (skb->encapsulation)
-                       features &= dev->hw_enc_features;
+struct sk_buff *validate_xmit_skb(struct sk_buff *skb, struct net_device *dev)
+{
+       netdev_features_t features;
 
-               if (netif_needs_gso(skb, features)) {
-                       if (unlikely(dev_gso_segment(skb, features)))
-                               goto out_kfree_skb;
-                       if (skb->next)
-                               goto gso;
-               } else {
-                       if (skb_needs_linearize(skb, features) &&
-                           __skb_linearize(skb))
-                               goto out_kfree_skb;
+       if (skb->next)
+               return skb;
 
-                       /* If packet is not checksummed and device does not
-                        * support checksumming for this protocol, complete
-                        * checksumming here.
-                        */
-                       if (skb->ip_summed == CHECKSUM_PARTIAL) {
-                               if (skb->encapsulation)
-                                       skb_set_inner_transport_header(skb,
-                                               skb_checksum_start_offset(skb));
-                               else
-                                       skb_set_transport_header(skb,
-                                               skb_checksum_start_offset(skb));
-                               if (!(features & NETIF_F_ALL_CSUM) &&
-                                    skb_checksum_help(skb))
-                                       goto out_kfree_skb;
-                       }
-               }
+       /* If device doesn't need skb->dst, release it right now while
+        * its hot in this cpu cache
+        */
+       if (dev->priv_flags & IFF_XMIT_DST_RELEASE)
+               skb_dst_drop(skb);
 
-               if (!list_empty(&ptype_all))
-                       dev_queue_xmit_nit(skb, dev);
+       features = netif_skb_features(skb);
+       skb = validate_xmit_vlan(skb, features);
+       if (unlikely(!skb))
+               goto out_null;
 
-               skb_len = skb->len;
-               trace_net_dev_start_xmit(skb, dev);
-               rc = ops->ndo_start_xmit(skb, dev);
-               trace_net_dev_xmit(skb, rc, dev, skb_len);
-               if (rc == NETDEV_TX_OK)
-                       txq_trans_update(txq);
-               return rc;
-       }
+       /* If encapsulation offload request, verify we are testing
+        * hardware encapsulation features instead of standard
+        * features for the netdev
+        */
+       if (skb->encapsulation)
+               features &= dev->hw_enc_features;
 
-gso:
-       do {
-               struct sk_buff *nskb = skb->next;
+       if (netif_needs_gso(skb, features)) {
+               struct sk_buff *segs;
 
-               skb->next = nskb->next;
-               nskb->next = NULL;
+               segs = skb_gso_segment(skb, features);
+               kfree_skb(skb);
+               if (IS_ERR(segs))
+                       segs = NULL;
+               skb = segs;
+       } else {
+               if (skb_needs_linearize(skb, features) &&
+                   __skb_linearize(skb))
+                       goto out_kfree_skb;
 
-               if (!list_empty(&ptype_all))
-                       dev_queue_xmit_nit(nskb, dev);
-
-               skb_len = nskb->len;
-               trace_net_dev_start_xmit(nskb, dev);
-               rc = ops->ndo_start_xmit(nskb, dev);
-               trace_net_dev_xmit(nskb, rc, dev, skb_len);
-               if (unlikely(rc != NETDEV_TX_OK)) {
-                       if (rc & ~NETDEV_TX_MASK)
-                               goto out_kfree_gso_skb;
-                       nskb->next = skb->next;
-                       skb->next = nskb;
-                       return rc;
+               /* If packet is not checksummed and device does not
+                * support checksumming for this protocol, complete
+                * checksumming here.
+                */
+               if (skb->ip_summed == CHECKSUM_PARTIAL) {
+                       if (skb->encapsulation)
+                               skb_set_inner_transport_header(skb,
+                                                              skb_checksum_start_offset(skb));
+                       else
+                               skb_set_transport_header(skb,
+                                                        skb_checksum_start_offset(skb));
+                       if (!(features & NETIF_F_ALL_CSUM) &&
+                           skb_checksum_help(skb))
+                               goto out_kfree_skb;
                }
-               txq_trans_update(txq);
-               if (unlikely(netif_xmit_stopped(txq) && skb->next))
-                       return NETDEV_TX_BUSY;
-       } while (skb->next);
-
-out_kfree_gso_skb:
-       if (likely(skb->next == NULL)) {
-               skb->destructor = DEV_GSO_CB(skb)->destructor;
-               consume_skb(skb);
-               return rc;
        }
+
+       return skb;
+
 out_kfree_skb:
        kfree_skb(skb);
-out:
-       return rc;
+out_null:
+       return NULL;
 }
-EXPORT_SYMBOL_GPL(dev_hard_start_xmit);
 
 static void qdisc_pkt_len_init(struct sk_buff *skb)
 {
@@ -2779,7 +2745,8 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q,
 
                qdisc_bstats_update(q, skb);
 
-               if (sch_direct_xmit(skb, q, dev, txq, root_lock)) {
+               skb = validate_xmit_skb(skb, dev);
+               if (skb && sch_direct_xmit(skb, q, dev, txq, root_lock)) {
                        if (unlikely(contended)) {
                                spin_unlock(&q->busylock);
                                contended = false;
@@ -2919,11 +2886,15 @@ static int __dev_queue_xmit(struct sk_buff *skb, void *accel_priv)
                        if (__this_cpu_read(xmit_recursion) > RECURSION_LIMIT)
                                goto recursion_alert;
 
+                       skb = validate_xmit_skb(skb, dev);
+                       if (!skb)
+                               goto drop;
+
                        HARD_TX_LOCK(dev, txq, cpu);
 
                        if (!netif_xmit_stopped(txq)) {
                                __this_cpu_inc(xmit_recursion);
-                               rc = dev_hard_start_xmit(skb, dev, txq);
+                               skb = dev_hard_start_xmit(skb, dev, txq, &rc);
                                __this_cpu_dec(xmit_recursion);
                                if (dev_xmit_complete(rc)) {
                                        HARD_TX_UNLOCK(dev, txq);
@@ -2944,10 +2915,11 @@ recursion_alert:
        }
 
        rc = -ENETDOWN;
+drop:
        rcu_read_unlock_bh();
 
        atomic_long_inc(&dev->tx_dropped);
-       kfree_skb(skb);
+       kfree_skb_list(skb);
        return rc;
 out:
        rcu_read_unlock_bh();
@@ -3124,8 +3096,7 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb,
        }
 
        if (map) {
-               tcpu = map->cpus[((u64) hash * map->len) >> 32];
-
+               tcpu = map->cpus[reciprocal_scale(hash, map->len)];
                if (cpu_online(tcpu)) {
                        cpu = tcpu;
                        goto done;
@@ -3959,11 +3930,10 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff
        if (!(skb->dev->features & NETIF_F_GRO))
                goto normal;
 
-       if (skb_is_gso(skb) || skb_has_frag_list(skb))
+       if (skb_is_gso(skb) || skb_has_frag_list(skb) || skb->csum_bad)
                goto normal;
 
        gro_list_prepare(napi, skb);
-       NAPI_GRO_CB(skb)->csum = skb->csum; /* Needed for CHECKSUM_COMPLETE */
 
        rcu_read_lock();
        list_for_each_entry_rcu(ptype, head, list) {
@@ -3977,6 +3947,22 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff
                NAPI_GRO_CB(skb)->free = 0;
                NAPI_GRO_CB(skb)->udp_mark = 0;
 
+               /* Setup for GRO checksum validation */
+               switch (skb->ip_summed) {
+               case CHECKSUM_COMPLETE:
+                       NAPI_GRO_CB(skb)->csum = skb->csum;
+                       NAPI_GRO_CB(skb)->csum_valid = 1;
+                       NAPI_GRO_CB(skb)->csum_cnt = 0;
+                       break;
+               case CHECKSUM_UNNECESSARY:
+                       NAPI_GRO_CB(skb)->csum_cnt = skb->csum_level + 1;
+                       NAPI_GRO_CB(skb)->csum_valid = 0;
+                       break;
+               default:
+                       NAPI_GRO_CB(skb)->csum_cnt = 0;
+                       NAPI_GRO_CB(skb)->csum_valid = 0;
+               }
+
                pp = ptype->callbacks.gro_receive(&napi->gro_list, skb);
                break;
        }
@@ -4206,6 +4192,31 @@ gro_result_t napi_gro_frags(struct napi_struct *napi)
 }
 EXPORT_SYMBOL(napi_gro_frags);
 
+/* Compute the checksum from gro_offset and return the folded value
+ * after adding in any pseudo checksum.
+ */
+__sum16 __skb_gro_checksum_complete(struct sk_buff *skb)
+{
+       __wsum wsum;
+       __sum16 sum;
+
+       wsum = skb_checksum(skb, skb_gro_offset(skb), skb_gro_len(skb), 0);
+
+       /* NAPI_GRO_CB(skb)->csum holds pseudo checksum */
+       sum = csum_fold(csum_add(NAPI_GRO_CB(skb)->csum, wsum));
+       if (likely(!sum)) {
+               if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE) &&
+                   !skb->csum_complete_sw)
+                       netdev_rx_csum_fault(skb->dev);
+       }
+
+       NAPI_GRO_CB(skb)->csum = wsum;
+       NAPI_GRO_CB(skb)->csum_valid = 1;
+
+       return sum;
+}
+EXPORT_SYMBOL(__skb_gro_checksum_complete);
+
 /*
  * net_rps_action_and_irq_enable sends any pending IPI's for rps.
  * Note: called with local irq disabled, but exits with local irq enabled.
@@ -4889,7 +4900,8 @@ static void __netdev_adjacent_dev_remove(struct net_device *dev,
        if (adj->master)
                sysfs_remove_link(&(dev->dev.kobj), "master");
 
-       if (netdev_adjacent_is_neigh_list(dev, dev_list))
+       if (netdev_adjacent_is_neigh_list(dev, dev_list) &&
+           net_eq(dev_net(dev),dev_net(adj_dev)))
                netdev_adjacent_sysfs_del(dev, adj_dev->name, dev_list);
 
        list_del_rcu(&adj->list);
@@ -5159,11 +5171,65 @@ void netdev_upper_dev_unlink(struct net_device *dev,
 }
 EXPORT_SYMBOL(netdev_upper_dev_unlink);
 
+void netdev_adjacent_add_links(struct net_device *dev)
+{
+       struct netdev_adjacent *iter;
+
+       struct net *net = dev_net(dev);
+
+       list_for_each_entry(iter, &dev->adj_list.upper, list) {
+               if (!net_eq(net,dev_net(iter->dev)))
+                       continue;
+               netdev_adjacent_sysfs_add(iter->dev, dev,
+                                         &iter->dev->adj_list.lower);
+               netdev_adjacent_sysfs_add(dev, iter->dev,
+                                         &dev->adj_list.upper);
+       }
+
+       list_for_each_entry(iter, &dev->adj_list.lower, list) {
+               if (!net_eq(net,dev_net(iter->dev)))
+                       continue;
+               netdev_adjacent_sysfs_add(iter->dev, dev,
+                                         &iter->dev->adj_list.upper);
+               netdev_adjacent_sysfs_add(dev, iter->dev,
+                                         &dev->adj_list.lower);
+       }
+}
+
+void netdev_adjacent_del_links(struct net_device *dev)
+{
+       struct netdev_adjacent *iter;
+
+       struct net *net = dev_net(dev);
+
+       list_for_each_entry(iter, &dev->adj_list.upper, list) {
+               if (!net_eq(net,dev_net(iter->dev)))
+                       continue;
+               netdev_adjacent_sysfs_del(iter->dev, dev->name,
+                                         &iter->dev->adj_list.lower);
+               netdev_adjacent_sysfs_del(dev, iter->dev->name,
+                                         &dev->adj_list.upper);
+       }
+
+       list_for_each_entry(iter, &dev->adj_list.lower, list) {
+               if (!net_eq(net,dev_net(iter->dev)))
+                       continue;
+               netdev_adjacent_sysfs_del(iter->dev, dev->name,
+                                         &iter->dev->adj_list.upper);
+               netdev_adjacent_sysfs_del(dev, iter->dev->name,
+                                         &dev->adj_list.lower);
+       }
+}
+
 void netdev_adjacent_rename_links(struct net_device *dev, char *oldname)
 {
        struct netdev_adjacent *iter;
 
+       struct net *net = dev_net(dev);
+
        list_for_each_entry(iter, &dev->adj_list.upper, list) {
+               if (!net_eq(net,dev_net(iter->dev)))
+                       continue;
                netdev_adjacent_sysfs_del(iter->dev, oldname,
                                          &iter->dev->adj_list.lower);
                netdev_adjacent_sysfs_add(iter->dev, dev,
@@ -5171,6 +5237,8 @@ void netdev_adjacent_rename_links(struct net_device *dev, char *oldname)
        }
 
        list_for_each_entry(iter, &dev->adj_list.lower, list) {
+               if (!net_eq(net,dev_net(iter->dev)))
+                       continue;
                netdev_adjacent_sysfs_del(iter->dev, oldname,
                                          &iter->dev->adj_list.upper);
                netdev_adjacent_sysfs_add(iter->dev, dev,
@@ -6773,6 +6841,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
 
        /* Send a netdev-removed uevent to the old namespace */
        kobject_uevent(&dev->dev.kobj, KOBJ_REMOVE);
+       netdev_adjacent_del_links(dev);
 
        /* Actually switch the network namespace */
        dev_net_set(dev, net);
@@ -6787,6 +6856,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
 
        /* Send a netdev-add uevent to the new namespace */
        kobject_uevent(&dev->dev.kobj, KOBJ_ADD);
+       netdev_adjacent_add_links(dev);
 
        /* Fixup kobjects */
        err = device_rename(&dev->dev, dev->name);
index cf999e09bcd2c23654826b8c7e7b3d3dde2a7a59..72e899a3efdaadd82877550d4991b70424cff5a2 100644 (file)
@@ -365,11 +365,8 @@ void dev_load(struct net *net, const char *name)
        no_module = !dev;
        if (no_module && capable(CAP_NET_ADMIN))
                no_module = request_module("netdev-%s", name);
-       if (no_module && capable(CAP_SYS_MODULE)) {
-               if (!request_module("%s", name))
-                       pr_warn("Loading kernel module for a network device with CAP_SYS_MODULE (deprecated).  Use CAP_NET_ADMIN and alias netdev-%s instead.\n",
-                               name);
-       }
+       if (no_module && capable(CAP_SYS_MODULE))
+               request_module("%s", name);
 }
 EXPORT_SYMBOL(dev_load);
 
index 17cb912793fa5ef0d221abda0dfb447b216b4268..27e61b886520895995e6e946555b0d766bf4a55e 100644 (file)
@@ -1621,6 +1621,80 @@ static int ethtool_get_module_eeprom(struct net_device *dev,
                                      modinfo.eeprom_len);
 }
 
+static int ethtool_tunable_valid(const struct ethtool_tunable *tuna)
+{
+       switch (tuna->id) {
+       case ETHTOOL_RX_COPYBREAK:
+               if (tuna->len != sizeof(u32) ||
+                   tuna->type_id != ETHTOOL_TUNABLE_U32)
+                       return -EINVAL;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int ethtool_get_tunable(struct net_device *dev, void __user *useraddr)
+{
+       int ret;
+       struct ethtool_tunable tuna;
+       const struct ethtool_ops *ops = dev->ethtool_ops;
+       void *data;
+
+       if (!ops->get_tunable)
+               return -EOPNOTSUPP;
+       if (copy_from_user(&tuna, useraddr, sizeof(tuna)))
+               return -EFAULT;
+       ret = ethtool_tunable_valid(&tuna);
+       if (ret)
+               return ret;
+       data = kmalloc(tuna.len, GFP_USER);
+       if (!data)
+               return -ENOMEM;
+       ret = ops->get_tunable(dev, &tuna, data);
+       if (ret)
+               goto out;
+       useraddr += sizeof(tuna);
+       ret = -EFAULT;
+       if (copy_to_user(useraddr, data, tuna.len))
+               goto out;
+       ret = 0;
+
+out:
+       kfree(data);
+       return ret;
+}
+
+static int ethtool_set_tunable(struct net_device *dev, void __user *useraddr)
+{
+       int ret;
+       struct ethtool_tunable tuna;
+       const struct ethtool_ops *ops = dev->ethtool_ops;
+       void *data;
+
+       if (!ops->set_tunable)
+               return -EOPNOTSUPP;
+       if (copy_from_user(&tuna, useraddr, sizeof(tuna)))
+               return -EFAULT;
+       ret = ethtool_tunable_valid(&tuna);
+       if (ret)
+               return ret;
+       data = kmalloc(tuna.len, GFP_USER);
+       if (!data)
+               return -ENOMEM;
+       useraddr += sizeof(tuna);
+       ret = -EFAULT;
+       if (copy_from_user(data, useraddr, tuna.len))
+               goto out;
+       ret = ops->set_tunable(dev, &tuna, data);
+
+out:
+       kfree(data);
+       return ret;
+}
+
 /* The main entry point in this file.  Called from net/core/dev_ioctl.c */
 
 int dev_ethtool(struct net *net, struct ifreq *ifr)
@@ -1670,6 +1744,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
        case ETHTOOL_GCHANNELS:
        case ETHTOOL_GET_TS_INFO:
        case ETHTOOL_GEEE:
+       case ETHTOOL_GTUNABLE:
                break;
        default:
                if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
@@ -1857,6 +1932,12 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
        case ETHTOOL_GMODULEEEPROM:
                rc = ethtool_get_module_eeprom(dev, useraddr);
                break;
+       case ETHTOOL_GTUNABLE:
+               rc = ethtool_get_tunable(dev, useraddr);
+               break;
+       case ETHTOOL_STUNABLE:
+               rc = ethtool_set_tunable(dev, useraddr);
+               break;
        default:
                rc = -EOPNOTSUPP;
        }
index d814b8a89d0f2f65efb95858f2e4fe26bf5a4ca9..dfc716ffa44b3b8264ddd4dffd293f5071f1d862 100644 (file)
@@ -113,7 +113,7 @@ static unsigned int pkt_type_offset(void)
 
 static u64 __skb_get_pay_offset(u64 ctx, u64 a, u64 x, u64 r4, u64 r5)
 {
-       return __skb_get_poff((struct sk_buff *)(unsigned long) ctx);
+       return skb_get_poff((struct sk_buff *)(unsigned long) ctx);
 }
 
 static u64 __skb_get_nlattr(u64 ctx, u64 a, u64 x, u64 r4, u64 r5)
@@ -933,7 +933,7 @@ static struct bpf_prog *bpf_migrate_filter(struct bpf_prog *fp)
 
        /* Expand fp for appending the new filter representation. */
        old_fp = fp;
-       fp = krealloc(old_fp, bpf_prog_size(new_len), GFP_KERNEL);
+       fp = bpf_prog_realloc(old_fp, bpf_prog_size(new_len), 0);
        if (!fp) {
                /* The old_fp is still around in case we couldn't
                 * allocate new memory, so uncharge on that one.
@@ -972,7 +972,7 @@ static struct bpf_prog *bpf_prepare_filter(struct bpf_prog *fp)
        int err;
 
        fp->bpf_func = NULL;
-       fp->jited = 0;
+       fp->jited = false;
 
        err = bpf_check_classic(fp->insns, fp->len);
        if (err) {
@@ -1013,7 +1013,7 @@ int bpf_prog_create(struct bpf_prog **pfp, struct sock_fprog_kern *fprog)
        if (fprog->filter == NULL)
                return -EINVAL;
 
-       fp = kmalloc(bpf_prog_size(fprog->len), GFP_KERNEL);
+       fp = bpf_prog_alloc(bpf_prog_size(fprog->len), 0);
        if (!fp)
                return -ENOMEM;
 
@@ -1069,7 +1069,7 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
        if (fprog->filter == NULL)
                return -EINVAL;
 
-       prog = kmalloc(bpf_fsize, GFP_KERNEL);
+       prog = bpf_prog_alloc(bpf_fsize, 0);
        if (!prog)
                return -ENOMEM;
 
index 5f362c1d03322692da59509c7d594f72255330b8..8560dea58803f947842e0be44d10464fb54127f6 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/if_pppox.h>
 #include <linux/ppp_defs.h>
 #include <net/flow_keys.h>
+#include <scsi/fc/fc_fcoe.h>
 
 /* copy saddr & daddr, possibly using 64bit load/store
  * Equivalent to :     flow->src = iph->saddr;
@@ -26,36 +27,61 @@ static void iph_to_flow_copy_addrs(struct flow_keys *flow, const struct iphdr *i
 }
 
 /**
- * skb_flow_get_ports - extract the upper layer ports and return them
- * @skb: buffer to extract the ports from
+ * __skb_flow_get_ports - extract the upper layer ports and return them
+ * @skb: sk_buff to extract the ports from
  * @thoff: transport header offset
  * @ip_proto: protocol for which to get port offset
+ * @data: raw buffer pointer to the packet, if NULL use skb->data
+ * @hlen: packet header length, if @data is NULL use skb_headlen(skb)
  *
  * The function will try to retrieve the ports at offset thoff + poff where poff
  * is the protocol port offset returned from proto_ports_offset
  */
-__be32 skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto)
+__be32 __skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto,
+                           void *data, int hlen)
 {
        int poff = proto_ports_offset(ip_proto);
 
+       if (!data) {
+               data = skb->data;
+               hlen = skb_headlen(skb);
+       }
+
        if (poff >= 0) {
                __be32 *ports, _ports;
 
-               ports = skb_header_pointer(skb, thoff + poff,
-                                          sizeof(_ports), &_ports);
+               ports = __skb_header_pointer(skb, thoff + poff,
+                                            sizeof(_ports), data, hlen, &_ports);
                if (ports)
                        return *ports;
        }
 
        return 0;
 }
-EXPORT_SYMBOL(skb_flow_get_ports);
+EXPORT_SYMBOL(__skb_flow_get_ports);
 
-bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow)
+/**
+ * __skb_flow_dissect - extract the flow_keys struct and return it
+ * @skb: sk_buff to extract the flow from, can be NULL if the rest are specified
+ * @data: raw buffer pointer to the packet, if NULL use skb->data
+ * @proto: protocol for which to get the flow, if @data is NULL use skb->protocol
+ * @nhoff: network header offset, if @data is NULL use skb_network_offset(skb)
+ * @hlen: packet header length, if @data is NULL use skb_headlen(skb)
+ *
+ * The function will try to retrieve the struct flow_keys from either the skbuff
+ * or a raw buffer specified by the rest parameters
+ */
+bool __skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow,
+                       void *data, __be16 proto, int nhoff, int hlen)
 {
-       int nhoff = skb_network_offset(skb);
        u8 ip_proto;
-       __be16 proto = skb->protocol;
+
+       if (!data) {
+               data = skb->data;
+               proto = skb->protocol;
+               nhoff = skb_network_offset(skb);
+               hlen = skb_headlen(skb);
+       }
 
        memset(flow, 0, sizeof(*flow));
 
@@ -65,7 +91,7 @@ again:
                const struct iphdr *iph;
                struct iphdr _iph;
 ip:
-               iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph);
+               iph = __skb_header_pointer(skb, nhoff, sizeof(_iph), data, hlen, &_iph);
                if (!iph || iph->ihl < 5)
                        return false;
                nhoff += iph->ihl * 4;
@@ -83,7 +109,7 @@ ip:
                __be32 flow_label;
 
 ipv6:
-               iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph);
+               iph = __skb_header_pointer(skb, nhoff, sizeof(_iph), data, hlen, &_iph);
                if (!iph)
                        return false;
 
@@ -92,6 +118,13 @@ ipv6:
                flow->dst = (__force __be32)ipv6_addr_hash(&iph->daddr);
                nhoff += sizeof(struct ipv6hdr);
 
+               /* skip the flow label processing if skb is NULL.  The
+                * assumption here is that if there is no skb we are not
+                * looking for flow info as much as we are length.
+                */
+               if (!skb)
+                       break;
+
                flow_label = ip6_flowlabel(iph);
                if (flow_label) {
                        /* Awesome, IPv6 packet has a flow label so we can
@@ -113,7 +146,7 @@ ipv6:
                const struct vlan_hdr *vlan;
                struct vlan_hdr _vlan;
 
-               vlan = skb_header_pointer(skb, nhoff, sizeof(_vlan), &_vlan);
+               vlan = __skb_header_pointer(skb, nhoff, sizeof(_vlan), data, hlen, &_vlan);
                if (!vlan)
                        return false;
 
@@ -126,7 +159,7 @@ ipv6:
                        struct pppoe_hdr hdr;
                        __be16 proto;
                } *hdr, _hdr;
-               hdr = skb_header_pointer(skb, nhoff, sizeof(_hdr), &_hdr);
+               hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hlen, &_hdr);
                if (!hdr)
                        return false;
                proto = hdr->proto;
@@ -140,6 +173,9 @@ ipv6:
                        return false;
                }
        }
+       case htons(ETH_P_FCOE):
+               flow->thoff = (u16)(nhoff + FCOE_HEADER_LEN);
+               /* fall through */
        default:
                return false;
        }
@@ -151,7 +187,7 @@ ipv6:
                        __be16 proto;
                } *hdr, _hdr;
 
-               hdr = skb_header_pointer(skb, nhoff, sizeof(_hdr), &_hdr);
+               hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hlen, &_hdr);
                if (!hdr)
                        return false;
                /*
@@ -171,8 +207,9 @@ ipv6:
                                const struct ethhdr *eth;
                                struct ethhdr _eth;
 
-                               eth = skb_header_pointer(skb, nhoff,
-                                                        sizeof(_eth), &_eth);
+                               eth = __skb_header_pointer(skb, nhoff,
+                                                          sizeof(_eth),
+                                                          data, hlen, &_eth);
                                if (!eth)
                                        return false;
                                proto = eth->h_proto;
@@ -194,12 +231,12 @@ ipv6:
 
        flow->n_proto = proto;
        flow->ip_proto = ip_proto;
-       flow->ports = skb_flow_get_ports(skb, nhoff, ip_proto);
+       flow->ports = __skb_flow_get_ports(skb, nhoff, ip_proto, data, hlen);
        flow->thoff = (u16) nhoff;
 
        return true;
 }
-EXPORT_SYMBOL(skb_flow_dissect);
+EXPORT_SYMBOL(__skb_flow_dissect);
 
 static u32 hashrnd __read_mostly;
 static __always_inline void __flow_hash_secret_init(void)
@@ -286,30 +323,22 @@ u16 __skb_tx_hash(const struct net_device *dev, struct sk_buff *skb,
                qcount = dev->tc_to_txq[tc].count;
        }
 
-       return (u16) (((u64)skb_get_hash(skb) * qcount) >> 32) + qoffset;
+       return (u16) reciprocal_scale(skb_get_hash(skb), qcount) + qoffset;
 }
 EXPORT_SYMBOL(__skb_tx_hash);
 
-/* __skb_get_poff() returns the offset to the payload as far as it could
- * be dissected. The main user is currently BPF, so that we can dynamically
- * truncate packets without needing to push actual payload to the user
- * space and can analyze headers only, instead.
- */
-u32 __skb_get_poff(const struct sk_buff *skb)
+u32 __skb_get_poff(const struct sk_buff *skb, void *data,
+                  const struct flow_keys *keys, int hlen)
 {
-       struct flow_keys keys;
-       u32 poff = 0;
-
-       if (!skb_flow_dissect(skb, &keys))
-               return 0;
+       u32 poff = keys->thoff;
 
-       poff += keys.thoff;
-       switch (keys.ip_proto) {
+       switch (keys->ip_proto) {
        case IPPROTO_TCP: {
                const struct tcphdr *tcph;
                struct tcphdr _tcph;
 
-               tcph = skb_header_pointer(skb, poff, sizeof(_tcph), &_tcph);
+               tcph = __skb_header_pointer(skb, poff, sizeof(_tcph),
+                                           data, hlen, &_tcph);
                if (!tcph)
                        return poff;
 
@@ -343,6 +372,21 @@ u32 __skb_get_poff(const struct sk_buff *skb)
        return poff;
 }
 
+/* skb_get_poff() returns the offset to the payload as far as it could
+ * be dissected. The main user is currently BPF, so that we can dynamically
+ * truncate packets without needing to push actual payload to the user
+ * space and can analyze headers only, instead.
+ */
+u32 skb_get_poff(const struct sk_buff *skb)
+{
+       struct flow_keys keys;
+
+       if (!skb_flow_dissect(skb, &keys))
+               return 0;
+
+       return __skb_get_poff(skb, skb->data, &keys, skb_headlen(skb));
+}
+
 static inline int get_xps_queue(struct net_device *dev, struct sk_buff *skb)
 {
 #ifdef CONFIG_XPS
@@ -359,9 +403,8 @@ static inline int get_xps_queue(struct net_device *dev, struct sk_buff *skb)
                        if (map->len == 1)
                                queue_index = map->queues[0];
                        else
-                               queue_index = map->queues[
-                                   ((u64)skb_get_hash(skb) * map->len) >> 32];
-
+                               queue_index = map->queues[reciprocal_scale(skb_get_hash(skb),
+                                                                          map->len)];
                        if (unlikely(queue_index >= dev->real_num_tx_queues))
                                queue_index = -1;
                }
index 6b5b6e7013cafec8a7b3767ed97a610bf35f1ae6..9d33dfffca19a992baf28e07ade0c7029c413ad0 100644 (file)
@@ -197,7 +197,7 @@ struct gen_estimator *gen_find_node(const struct gnet_stats_basic_packed *bstats
  * as destination. A new timer with the interval specified in the
  * configuration TLV is created. Upon each interval, the latest statistics
  * will be read from &bstats and the estimated rate will be stored in
- * &rate_est with the statistics lock grabed during this period.
+ * &rate_est with the statistics lock grabbed during this period.
  *
  * Returns 0 on success or a negative error code.
  *
index 9d3d9e78397b0f90f379addab25c7fd78294b3bc..2ddbce4cce144f62e8fed9dd39209fb3429b82a7 100644 (file)
@@ -206,7 +206,7 @@ EXPORT_SYMBOL(gnet_stats_copy_queue);
  * @st: application specific statistics data
  * @len: length of data
  *
- * Appends the application sepecific statistics to the top level TLV created by
+ * Appends the application specific statistics to the top level TLV created by
  * gnet_stats_start_copy() and remembers the data for XSTATS if the dumping
  * handle is in backward compatibility mode.
  *
index 7c6b51a58968613010576f3bd35a3cb6c527db08..7f155175bba83a0c8083008ece1a56e265174984 100644 (file)
@@ -224,7 +224,7 @@ static void net_free(struct net *net)
                return;
        }
 #endif
-       kfree(net->gen);
+       kfree(rcu_access_pointer(net->gen));
        kmem_cache_free(net_cachep, net);
 }
 
index 907fb5e36c02e54794734abe4dc1225bf9af9c7d..e6645b4f330af1d16607ca0d6d9c9c95fd163dc6 100644 (file)
@@ -72,7 +72,6 @@ module_param(carrier_timeout, uint, 0644);
 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;
 
@@ -92,9 +91,7 @@ static int netpoll_start_xmit(struct sk_buff *skb, struct net_device *dev,
                skb->vlan_tci = 0;
        }
 
-       status = ops->ndo_start_xmit(skb, dev);
-       if (status == NETDEV_TX_OK)
-               txq_trans_update(txq);
+       status = netdev_start_xmit(skb, dev, txq, false);
 
 out:
        return status;
@@ -116,7 +113,7 @@ static void queue_process(struct work_struct *work)
                        continue;
                }
 
-               txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb));
+               txq = skb_get_tx_queue(dev, skb);
 
                local_irq_save(flags);
                HARD_TX_LOCK(dev, txq, smp_processor_id());
index 8b849ddfef2e743676fe35642cd49d36188dd74d..5c728aaf8d6c75568e66730939d6dac50dadf0d9 100644 (file)
 #define F_QUEUE_MAP_CPU (1<<14)        /* queue map mirrors smp_processor_id() */
 #define F_NODE          (1<<15)        /* Node memory alloc*/
 #define F_UDPCSUM       (1<<16)        /* Include UDP checksum */
+#define F_NO_TIMESTAMP  (1<<17)        /* Don't timestamp packets (default TS) */
 
 /* Thread control flag bits */
 #define T_STOP        (1<<0)   /* Stop run */
@@ -505,7 +506,7 @@ static ssize_t pgctrl_write(struct file *file, const char __user *buf,
                pktgen_reset_all_threads(pn);
 
        else
-               pr_warning("Unknown command: %s\n", data);
+               pr_warn("Unknown command: %s\n", data);
 
        return count;
 }
@@ -638,6 +639,9 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
        if (pkt_dev->flags & F_UDPCSUM)
                seq_puts(seq, "UDPCSUM  ");
 
+       if (pkt_dev->flags & F_NO_TIMESTAMP)
+               seq_puts(seq, "NO_TIMESTAMP  ");
+
        if (pkt_dev->flags & F_MPLS_RND)
                seq_puts(seq,  "MPLS_RND  ");
 
@@ -857,14 +861,14 @@ static ssize_t pktgen_if_write(struct file *file,
        pg_result = &(pkt_dev->result[0]);
 
        if (count < 1) {
-               pr_warning("wrong command format\n");
+               pr_warn("wrong command format\n");
                return -EINVAL;
        }
 
        max = count;
        tmp = count_trail_chars(user_buffer, max);
        if (tmp < 0) {
-               pr_warning("illegal format\n");
+               pr_warn("illegal format\n");
                return tmp;
        }
        i = tmp;
@@ -1243,6 +1247,9 @@ static ssize_t pktgen_if_write(struct file *file,
                else if (strcmp(f, "!UDPCSUM") == 0)
                        pkt_dev->flags &= ~F_UDPCSUM;
 
+               else if (strcmp(f, "NO_TIMESTAMP") == 0)
+                       pkt_dev->flags |= F_NO_TIMESTAMP;
+
                else {
                        sprintf(pg_result,
                                "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s",
@@ -1251,6 +1258,7 @@ static ssize_t pktgen_if_write(struct file *file,
                                "MACSRC_RND, MACDST_RND, TXSIZE_RND, IPV6, "
                                "MPLS_RND, VID_RND, SVID_RND, FLOW_SEQ, "
                                "QUEUE_MAP_RND, QUEUE_MAP_CPU, UDPCSUM, "
+                               "NO_TIMESTAMP, "
 #ifdef CONFIG_XFRM
                                "IPSEC, "
 #endif
@@ -2048,15 +2056,15 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev)
        ntxq = pkt_dev->odev->real_num_tx_queues;
 
        if (ntxq <= pkt_dev->queue_map_min) {
-               pr_warning("WARNING: Requested queue_map_min (zero-based) (%d) exceeds valid range [0 - %d] for (%d) queues on %s, resetting\n",
-                          pkt_dev->queue_map_min, (ntxq ?: 1) - 1, ntxq,
-                          pkt_dev->odevname);
+               pr_warn("WARNING: Requested queue_map_min (zero-based) (%d) exceeds valid range [0 - %d] for (%d) queues on %s, resetting\n",
+                       pkt_dev->queue_map_min, (ntxq ?: 1) - 1, ntxq,
+                       pkt_dev->odevname);
                pkt_dev->queue_map_min = (ntxq ?: 1) - 1;
        }
        if (pkt_dev->queue_map_max >= ntxq) {
-               pr_warning("WARNING: Requested queue_map_max (zero-based) (%d) exceeds valid range [0 - %d] for (%d) queues on %s, resetting\n",
-                          pkt_dev->queue_map_max, (ntxq ?: 1) - 1, ntxq,
-                          pkt_dev->odevname);
+               pr_warn("WARNING: Requested queue_map_max (zero-based) (%d) exceeds valid range [0 - %d] for (%d) queues on %s, resetting\n",
+                       pkt_dev->queue_map_max, (ntxq ?: 1) - 1, ntxq,
+                       pkt_dev->odevname);
                pkt_dev->queue_map_max = (ntxq ?: 1) - 1;
        }
 
@@ -2685,9 +2693,14 @@ static void pktgen_finalize_skb(struct pktgen_dev *pkt_dev, struct sk_buff *skb,
        pgh->pgh_magic = htonl(PKTGEN_MAGIC);
        pgh->seq_num = htonl(pkt_dev->seq_num);
 
-       do_gettimeofday(&timestamp);
-       pgh->tv_sec = htonl(timestamp.tv_sec);
-       pgh->tv_usec = htonl(timestamp.tv_usec);
+       if (pkt_dev->flags & F_NO_TIMESTAMP) {
+               pgh->tv_sec = 0;
+               pgh->tv_usec = 0;
+       } else {
+               do_gettimeofday(&timestamp);
+               pgh->tv_sec = htonl(timestamp.tv_sec);
+               pgh->tv_usec = htonl(timestamp.tv_usec);
+       }
 }
 
 static struct sk_buff *pktgen_alloc_skb(struct net_device *dev,
@@ -3160,8 +3173,8 @@ static int pktgen_stop_device(struct pktgen_dev *pkt_dev)
        int nr_frags = pkt_dev->skb ? skb_shinfo(pkt_dev->skb)->nr_frags : -1;
 
        if (!pkt_dev->running) {
-               pr_warning("interface: %s is already stopped\n",
-                          pkt_dev->odevname);
+               pr_warn("interface: %s is already stopped\n",
+                       pkt_dev->odevname);
                return -EINVAL;
        }
 
@@ -3285,10 +3298,7 @@ static void pktgen_wait_for_skb(struct pktgen_dev *pkt_dev)
 static void pktgen_xmit(struct pktgen_dev *pkt_dev)
 {
        struct net_device *odev = pkt_dev->odev;
-       netdev_tx_t (*xmit)(struct sk_buff *, struct net_device *)
-               = odev->netdev_ops->ndo_start_xmit;
        struct netdev_queue *txq;
-       u16 queue_map;
        int ret;
 
        /* If device is offline, then don't send */
@@ -3326,8 +3336,7 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev)
        if (pkt_dev->delay && pkt_dev->last_ok)
                spin(pkt_dev, pkt_dev->next_tx);
 
-       queue_map = skb_get_queue_mapping(pkt_dev->skb);
-       txq = netdev_get_tx_queue(odev, queue_map);
+       txq = skb_get_tx_queue(odev, pkt_dev->skb);
 
        local_bh_disable();
 
@@ -3339,11 +3348,10 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev)
                goto unlock;
        }
        atomic_inc(&(pkt_dev->skb->users));
-       ret = (*xmit)(pkt_dev->skb, odev);
+       ret = netdev_start_xmit(pkt_dev->skb, odev, txq, false);
 
        switch (ret) {
        case NETDEV_TX_OK:
-               txq_trans_update(txq);
                pkt_dev->last_ok = 1;
                pkt_dev->sofar++;
                pkt_dev->seq_num++;
@@ -3684,7 +3692,7 @@ static int pktgen_remove_device(struct pktgen_thread *t,
        pr_debug("remove_device pkt_dev=%p\n", pkt_dev);
 
        if (pkt_dev->running) {
-               pr_warning("WARNING: trying to remove a running interface, stopping it now\n");
+               pr_warn("WARNING: trying to remove a running interface, stopping it now\n");
                pktgen_stop_device(pkt_dev);
        }
 
index f0493e3b7471099f0245b0ea0c4b52de4a03034f..a6882686ca3a10fc3be7ced6299dc7385ffd239d 100644 (file)
@@ -1481,9 +1481,12 @@ static int do_set_master(struct net_device *dev, int ifindex)
        return 0;
 }
 
+#define DO_SETLINK_MODIFIED    0x01
+/* notify flag means notify + modified. */
+#define DO_SETLINK_NOTIFY      0x03
 static int do_setlink(const struct sk_buff *skb,
                      struct net_device *dev, struct ifinfomsg *ifm,
-                     struct nlattr **tb, char *ifname, int modified)
+                     struct nlattr **tb, char *ifname, int status)
 {
        const struct net_device_ops *ops = dev->netdev_ops;
        int err;
@@ -1502,7 +1505,7 @@ static int do_setlink(const struct sk_buff *skb,
                put_net(net);
                if (err)
                        goto errout;
-               modified = 1;
+               status |= DO_SETLINK_MODIFIED;
        }
 
        if (tb[IFLA_MAP]) {
@@ -1531,7 +1534,7 @@ static int do_setlink(const struct sk_buff *skb,
                if (err < 0)
                        goto errout;
 
-               modified = 1;
+               status |= DO_SETLINK_NOTIFY;
        }
 
        if (tb[IFLA_ADDRESS]) {
@@ -1551,19 +1554,19 @@ static int do_setlink(const struct sk_buff *skb,
                kfree(sa);
                if (err)
                        goto errout;
-               modified = 1;
+               status |= DO_SETLINK_MODIFIED;
        }
 
        if (tb[IFLA_MTU]) {
                err = dev_set_mtu(dev, nla_get_u32(tb[IFLA_MTU]));
                if (err < 0)
                        goto errout;
-               modified = 1;
+               status |= DO_SETLINK_MODIFIED;
        }
 
        if (tb[IFLA_GROUP]) {
                dev_set_group(dev, nla_get_u32(tb[IFLA_GROUP]));
-               modified = 1;
+               status |= DO_SETLINK_NOTIFY;
        }
 
        /*
@@ -1575,7 +1578,7 @@ static int do_setlink(const struct sk_buff *skb,
                err = dev_change_name(dev, ifname);
                if (err < 0)
                        goto errout;
-               modified = 1;
+               status |= DO_SETLINK_MODIFIED;
        }
 
        if (tb[IFLA_IFALIAS]) {
@@ -1583,7 +1586,7 @@ static int do_setlink(const struct sk_buff *skb,
                                    nla_len(tb[IFLA_IFALIAS]));
                if (err < 0)
                        goto errout;
-               modified = 1;
+               status |= DO_SETLINK_NOTIFY;
        }
 
        if (tb[IFLA_BROADCAST]) {
@@ -1601,25 +1604,35 @@ static int do_setlink(const struct sk_buff *skb,
                err = do_set_master(dev, nla_get_u32(tb[IFLA_MASTER]));
                if (err)
                        goto errout;
-               modified = 1;
+               status |= DO_SETLINK_MODIFIED;
        }
 
        if (tb[IFLA_CARRIER]) {
                err = dev_change_carrier(dev, nla_get_u8(tb[IFLA_CARRIER]));
                if (err)
                        goto errout;
-               modified = 1;
+               status |= DO_SETLINK_MODIFIED;
        }
 
-       if (tb[IFLA_TXQLEN])
-               dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]);
+       if (tb[IFLA_TXQLEN]) {
+               unsigned long value = nla_get_u32(tb[IFLA_TXQLEN]);
+
+               if (dev->tx_queue_len ^ value)
+                       status |= DO_SETLINK_NOTIFY;
+
+               dev->tx_queue_len = value;
+       }
 
        if (tb[IFLA_OPERSTATE])
                set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE]));
 
        if (tb[IFLA_LINKMODE]) {
+               unsigned char value = nla_get_u8(tb[IFLA_LINKMODE]);
+
                write_lock_bh(&dev_base_lock);
-               dev->link_mode = nla_get_u8(tb[IFLA_LINKMODE]);
+               if (dev->link_mode ^ value)
+                       status |= DO_SETLINK_NOTIFY;
+               dev->link_mode = value;
                write_unlock_bh(&dev_base_lock);
        }
 
@@ -1634,7 +1647,7 @@ static int do_setlink(const struct sk_buff *skb,
                        err = do_setvfinfo(dev, attr);
                        if (err < 0)
                                goto errout;
-                       modified = 1;
+                       status |= DO_SETLINK_NOTIFY;
                }
        }
        err = 0;
@@ -1664,7 +1677,7 @@ static int do_setlink(const struct sk_buff *skb,
                        err = ops->ndo_set_vf_port(dev, vf, port);
                        if (err < 0)
                                goto errout;
-                       modified = 1;
+                       status |= DO_SETLINK_NOTIFY;
                }
        }
        err = 0;
@@ -1682,7 +1695,7 @@ static int do_setlink(const struct sk_buff *skb,
                        err = ops->ndo_set_vf_port(dev, PORT_SELF_VF, port);
                if (err < 0)
                        goto errout;
-               modified = 1;
+               status |= DO_SETLINK_NOTIFY;
        }
 
        if (tb[IFLA_AF_SPEC]) {
@@ -1699,15 +1712,20 @@ static int do_setlink(const struct sk_buff *skb,
                        if (err < 0)
                                goto errout;
 
-                       modified = 1;
+                       status |= DO_SETLINK_NOTIFY;
                }
        }
        err = 0;
 
 errout:
-       if (err < 0 && modified)
-               net_warn_ratelimited("A link change request failed with some changes committed already. Interface %s may have been left with an inconsistent configuration, please check.\n",
-                                    dev->name);
+       if (status & DO_SETLINK_MODIFIED) {
+               if (status & DO_SETLINK_NOTIFY)
+                       netdev_state_change(dev);
+
+               if (err < 0)
+                       net_warn_ratelimited("A link change request failed with some changes committed already. Interface %s may have been left with an inconsistent configuration, please check.\n",
+                                            dev->name);
+       }
 
        return err;
 }
@@ -1989,7 +2007,7 @@ replay:
                }
 
                if (dev) {
-                       int modified = 0;
+                       int status = 0;
 
                        if (nlh->nlmsg_flags & NLM_F_EXCL)
                                return -EEXIST;
@@ -2004,7 +2022,7 @@ replay:
                                err = ops->changelink(dev, tb, data);
                                if (err < 0)
                                        return err;
-                               modified = 1;
+                               status |= DO_SETLINK_NOTIFY;
                        }
 
                        if (linkinfo[IFLA_INFO_SLAVE_DATA]) {
@@ -2015,10 +2033,10 @@ replay:
                                                              tb, slave_data);
                                if (err < 0)
                                        return err;
-                               modified = 1;
+                               status |= DO_SETLINK_NOTIFY;
                        }
 
-                       return do_setlink(skb, dev, ifm, tb, ifname, modified);
+                       return do_setlink(skb, dev, ifm, tb, ifname, status);
                }
 
                if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
index ba71212f0251218c3c41599838e36aa8e169fea7..51dd3193a33ebb26ea3c008e752d1f2832f791d8 100644 (file)
@@ -35,7 +35,7 @@ static u32 seq_scale(u32 seq)
         *      overlaps less than one time per MSL (2 minutes).
         *      Choosing a clock of 64 ns period is OK. (period of 274 s)
         */
-       return seq + (ktime_to_ns(ktime_get_real()) >> 6);
+       return seq + (ktime_get_real_ns() >> 6);
 }
 #endif
 
@@ -135,7 +135,7 @@ u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr,
        md5_transform(hash, net_secret);
 
        seq = hash[0] | (((u64)hash[1]) << 32);
-       seq += ktime_to_ns(ktime_get_real());
+       seq += ktime_get_real_ns();
        seq &= (1ull << 48) - 1;
 
        return seq;
@@ -163,7 +163,7 @@ u64 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr,
        md5_transform(hash, secret);
 
        seq = hash[0] | (((u64)hash[1]) << 32);
-       seq += ktime_to_ns(ktime_get_real());
+       seq += ktime_get_real_ns();
        seq &= (1ull << 48) - 1;
 
        return seq;
index 163b673f9e62d212230abd1c9b848c35ba923a0d..a18dfb02d94492647a50a88797e47d0f698ad62b 100644 (file)
@@ -2647,7 +2647,7 @@ EXPORT_SYMBOL(skb_prepare_seq_read);
  * skb_seq_read() will return the remaining part of the block.
  *
  * Note 1: The size of each block of data returned can be arbitrary,
- *       this limitation is the cost for zerocopy seqeuental
+ *       this limitation is the cost for zerocopy sequential
  *       reads of potentially non linear data.
  *
  * Note 2: Fragment lists within fragments are not implemented
@@ -2781,7 +2781,7 @@ EXPORT_SYMBOL(skb_find_text);
 /**
  * skb_append_datato_frags - append the user data to a skb
  * @sk: sock  structure
- * @skb: skb structure to be appened with user data.
+ * @skb: skb structure to be appended with user data.
  * @getfrag: call back function to be used for getting the user data
  * @from: pointer to user message iov
  * @length: length of the iov message
@@ -3491,32 +3491,53 @@ int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb)
 }
 EXPORT_SYMBOL(sock_queue_err_skb);
 
-void __skb_tstamp_tx(struct sk_buff *orig_skb,
-                    struct skb_shared_hwtstamps *hwtstamps,
-                    struct sock *sk, int tstype)
+struct sk_buff *sock_dequeue_err_skb(struct sock *sk)
 {
-       struct sock_exterr_skb *serr;
-       struct sk_buff *skb;
-       int err;
+       struct sk_buff_head *q = &sk->sk_error_queue;
+       struct sk_buff *skb, *skb_next;
+       int err = 0;
 
-       if (!sk)
-               return;
+       spin_lock_bh(&q->lock);
+       skb = __skb_dequeue(q);
+       if (skb && (skb_next = skb_peek(q)))
+               err = SKB_EXT_ERR(skb_next)->ee.ee_errno;
+       spin_unlock_bh(&q->lock);
 
-       if (hwtstamps) {
-               *skb_hwtstamps(orig_skb) =
-                       *hwtstamps;
-       } else {
-               /*
-                * no hardware time stamps available,
-                * so keep the shared tx_flags and only
-                * store software time stamp
-                */
-               orig_skb->tstamp = ktime_get_real();
+       sk->sk_err = err;
+       if (err)
+               sk->sk_error_report(sk);
+
+       return skb;
+}
+EXPORT_SYMBOL(sock_dequeue_err_skb);
+
+struct sk_buff *skb_clone_sk(struct sk_buff *skb)
+{
+       struct sock *sk = skb->sk;
+       struct sk_buff *clone;
+
+       if (!sk || !atomic_inc_not_zero(&sk->sk_refcnt))
+               return NULL;
+
+       clone = skb_clone(skb, GFP_ATOMIC);
+       if (!clone) {
+               sock_put(sk);
+               return NULL;
        }
 
-       skb = skb_clone(orig_skb, GFP_ATOMIC);
-       if (!skb)
-               return;
+       clone->sk = sk;
+       clone->destructor = sock_efree;
+
+       return clone;
+}
+EXPORT_SYMBOL(skb_clone_sk);
+
+static void __skb_complete_tx_timestamp(struct sk_buff *skb,
+                                       struct sock *sk,
+                                       int tstype)
+{
+       struct sock_exterr_skb *serr;
+       int err;
 
        serr = SKB_EXT_ERR(skb);
        memset(serr, 0, sizeof(*serr));
@@ -3534,6 +3555,42 @@ void __skb_tstamp_tx(struct sk_buff *orig_skb,
        if (err)
                kfree_skb(skb);
 }
+
+void skb_complete_tx_timestamp(struct sk_buff *skb,
+                              struct skb_shared_hwtstamps *hwtstamps)
+{
+       struct sock *sk = skb->sk;
+
+       /* take a reference to prevent skb_orphan() from freeing the socket */
+       sock_hold(sk);
+
+       *skb_hwtstamps(skb) = *hwtstamps;
+       __skb_complete_tx_timestamp(skb, sk, SCM_TSTAMP_SND);
+
+       sock_put(sk);
+}
+EXPORT_SYMBOL_GPL(skb_complete_tx_timestamp);
+
+void __skb_tstamp_tx(struct sk_buff *orig_skb,
+                    struct skb_shared_hwtstamps *hwtstamps,
+                    struct sock *sk, int tstype)
+{
+       struct sk_buff *skb;
+
+       if (!sk)
+               return;
+
+       if (hwtstamps)
+               *skb_hwtstamps(orig_skb) = *hwtstamps;
+       else
+               orig_skb->tstamp = ktime_get_real();
+
+       skb = skb_clone(orig_skb, GFP_ATOMIC);
+       if (!skb)
+               return;
+
+       __skb_complete_tx_timestamp(skb, sk, tstype);
+}
 EXPORT_SYMBOL_GPL(__skb_tstamp_tx);
 
 void skb_tstamp_tx(struct sk_buff *orig_skb,
index 2714811afbd8bd3d35b5bd8619179eafaa71e19b..6f436b5e49611aee6d0e21fc3cdcccdbd8a82a08 100644 (file)
@@ -166,7 +166,7 @@ EXPORT_SYMBOL(sk_ns_capable);
 /**
  * sk_capable - Socket global capability test
  * @sk: Socket to use a capability on or through
- * @cap: The global capbility to use
+ * @cap: The global capability to use
  *
  * Test to see if the opener of the socket had when the socket was
  * created and the current process has the capability @cap in all user
@@ -183,7 +183,7 @@ EXPORT_SYMBOL(sk_capable);
  * @sk: Socket to use a capability on or through
  * @cap: The capability to use
  *
- * Test to see if the opener of the socket had when the socke was created
+ * Test to see if the opener of the socket had when the socket was created
  * and the current process has the capability @cap over the network namespace
  * the socket is a member of.
  */
@@ -437,7 +437,6 @@ static void sock_disable_timestamp(struct sock *sk, unsigned long flags)
 int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
 {
        int err;
-       int skb_len;
        unsigned long flags;
        struct sk_buff_head *list = &sk->sk_receive_queue;
 
@@ -459,13 +458,6 @@ int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
        skb->dev = NULL;
        skb_set_owner_r(skb, sk);
 
-       /* Cache the SKB length before we tack it onto the receive
-        * queue.  Once it is added it no longer belongs to us and
-        * may be freed by other threads of control pulling packets
-        * from the queue.
-        */
-       skb_len = skb->len;
-
        /* we escape from rcu protected region, make sure we dont leak
         * a norefcounted dst
         */
@@ -1645,18 +1637,24 @@ void sock_rfree(struct sk_buff *skb)
 }
 EXPORT_SYMBOL(sock_rfree);
 
+void sock_efree(struct sk_buff *skb)
+{
+       sock_put(skb->sk);
+}
+EXPORT_SYMBOL(sock_efree);
+
+#ifdef CONFIG_INET
 void sock_edemux(struct sk_buff *skb)
 {
        struct sock *sk = skb->sk;
 
-#ifdef CONFIG_INET
        if (sk->sk_state == TCP_TIME_WAIT)
                inet_twsk_put(inet_twsk(sk));
        else
-#endif
                sock_put(sk);
 }
 EXPORT_SYMBOL(sock_edemux);
+#endif
 
 kuid_t sock_i_uid(struct sock *sk)
 {
@@ -1822,6 +1820,9 @@ struct sk_buff *sock_alloc_send_pskb(struct sock *sk, unsigned long header_len,
                                                           order);
                                        if (page)
                                                goto fill_page;
+                                       /* Do not retry other high order allocations */
+                                       order = 1;
+                                       max_page_order = 0;
                                }
                                order--;
                        }
@@ -1869,10 +1870,8 @@ EXPORT_SYMBOL(sock_alloc_send_skb);
  * no guarantee that allocations succeed. Therefore, @sz MUST be
  * less or equal than PAGE_SIZE.
  */
-bool skb_page_frag_refill(unsigned int sz, struct page_frag *pfrag, gfp_t prio)
+bool skb_page_frag_refill(unsigned int sz, struct page_frag *pfrag, gfp_t gfp)
 {
-       int order;
-
        if (pfrag->page) {
                if (atomic_read(&pfrag->page->_count) == 1) {
                        pfrag->offset = 0;
@@ -1883,20 +1882,21 @@ bool skb_page_frag_refill(unsigned int sz, struct page_frag *pfrag, gfp_t prio)
                put_page(pfrag->page);
        }
 
-       order = SKB_FRAG_PAGE_ORDER;
-       do {
-               gfp_t gfp = prio;
-
-               if (order)
-                       gfp |= __GFP_COMP | __GFP_NOWARN | __GFP_NORETRY;
-               pfrag->page = alloc_pages(gfp, order);
+       pfrag->offset = 0;
+       if (SKB_FRAG_PAGE_ORDER) {
+               pfrag->page = alloc_pages(gfp | __GFP_COMP |
+                                         __GFP_NOWARN | __GFP_NORETRY,
+                                         SKB_FRAG_PAGE_ORDER);
                if (likely(pfrag->page)) {
-                       pfrag->offset = 0;
-                       pfrag->size = PAGE_SIZE << order;
+                       pfrag->size = PAGE_SIZE << SKB_FRAG_PAGE_ORDER;
                        return true;
                }
-       } while (--order >= 0);
-
+       }
+       pfrag->page = alloc_page(gfp);
+       if (likely(pfrag->page)) {
+               pfrag->size = PAGE_SIZE;
+               return true;
+       }
        return false;
 }
 EXPORT_SYMBOL(skb_page_frag_refill);
@@ -2496,11 +2496,11 @@ int sock_recv_errqueue(struct sock *sk, struct msghdr *msg, int len,
                       int level, int type)
 {
        struct sock_exterr_skb *serr;
-       struct sk_buff *skb, *skb2;
+       struct sk_buff *skb;
        int copied, err;
 
        err = -EAGAIN;
-       skb = skb_dequeue(&sk->sk_error_queue);
+       skb = sock_dequeue_err_skb(sk);
        if (skb == NULL)
                goto out;
 
@@ -2521,16 +2521,6 @@ int sock_recv_errqueue(struct sock *sk, struct msghdr *msg, int len,
        msg->msg_flags |= MSG_ERRQUEUE;
        err = copied;
 
-       /* Reset and regenerate socket error */
-       spin_lock_bh(&sk->sk_error_queue.lock);
-       sk->sk_err = 0;
-       if ((skb2 = skb_peek(&sk->sk_error_queue)) != NULL) {
-               sk->sk_err = SKB_EXT_ERR(skb2)->ee.ee_errno;
-               spin_unlock_bh(&sk->sk_error_queue.lock);
-               sk->sk_error_report(sk);
-       } else
-               spin_unlock_bh(&sk->sk_error_queue.lock);
-
 out_free_skb:
        kfree_skb(skb);
 out:
index a8770391ea5bfc0db85135cf913c84d09f55cedb..43d3dd62fcc8eccd95a4618f68b0553cf7309c01 100644 (file)
@@ -36,10 +36,9 @@ void skb_clone_tx_timestamp(struct sk_buff *skb)
 {
        struct phy_device *phydev;
        struct sk_buff *clone;
-       struct sock *sk = skb->sk;
        unsigned int type;
 
-       if (!sk)
+       if (!skb->sk)
                return;
 
        type = classify(skb);
@@ -48,50 +47,14 @@ void skb_clone_tx_timestamp(struct sk_buff *skb)
 
        phydev = skb->dev->phydev;
        if (likely(phydev->drv->txtstamp)) {
-               if (!atomic_inc_not_zero(&sk->sk_refcnt))
+               clone = skb_clone_sk(skb);
+               if (!clone)
                        return;
-
-               clone = skb_clone(skb, GFP_ATOMIC);
-               if (!clone) {
-                       sock_put(sk);
-                       return;
-               }
-
-               clone->sk = sk;
                phydev->drv->txtstamp(phydev, clone, type);
        }
 }
 EXPORT_SYMBOL_GPL(skb_clone_tx_timestamp);
 
-void skb_complete_tx_timestamp(struct sk_buff *skb,
-                              struct skb_shared_hwtstamps *hwtstamps)
-{
-       struct sock *sk = skb->sk;
-       struct sock_exterr_skb *serr;
-       int err;
-
-       if (!hwtstamps) {
-               sock_put(sk);
-               kfree_skb(skb);
-               return;
-       }
-
-       *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);
-}
-EXPORT_SYMBOL_GPL(skb_complete_tx_timestamp);
-
 bool skb_defer_rx_timestamp(struct sk_buff *skb)
 {
        struct phy_device *phydev;
index ae011b46c0710fc96204deda6bddb1d912d78f22..25733d53814763c85e49a612df3bbcdb202992d6 100644 (file)
@@ -127,6 +127,7 @@ Version 0.0.6    2.1.110   07-aug-98   Eduardo Marcelo Serrat
 #include <linux/stat.h>
 #include <linux/init.h>
 #include <linux/poll.h>
+#include <linux/jiffies.h>
 #include <net/net_namespace.h>
 #include <net/neighbour.h>
 #include <net/dst.h>
@@ -598,7 +599,7 @@ int dn_destroy_timer(struct sock *sk)
        if (sk->sk_socket)
                return 0;
 
-       if ((jiffies - scp->stamp) >= (HZ * decnet_time_wait)) {
+       if (time_after_eq(jiffies, scp->stamp + HZ * decnet_time_wait)) {
                dn_unhash_sock(sk);
                sock_put(sk);
                return 1;
index 3b726f31c64c0b88efcfacd4d64df7177260ad5c..4400da7739dafb3c3d42e52829086b9d3e418505 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/sysctl.h>
 #include <linux/notifier.h>
 #include <linux/slab.h>
+#include <linux/jiffies.h>
 #include <asm/uaccess.h>
 #include <net/net_namespace.h>
 #include <net/neighbour.h>
@@ -875,7 +876,7 @@ static void dn_send_endnode_hello(struct net_device *dev, struct dn_ifaddr *ifa)
 static int dn_am_i_a_router(struct dn_neigh *dn, struct dn_dev *dn_db, struct dn_ifaddr *ifa)
 {
        /* First check time since device went up */
-       if ((jiffies - dn_db->uptime) < DRDELAY)
+       if (time_before(jiffies, dn_db->uptime + DRDELAY))
                return 0;
 
        /* If there is no router, then yes... */
index d9c150cc59a952ac86585b6c600acc398b80bc14..1d330fd43dc7e177d162f77796d2142a4e563fdb 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/spinlock.h>
 #include <net/sock.h>
 #include <linux/atomic.h>
+#include <linux/jiffies.h>
 #include <net/flow.h>
 #include <net/dn.h>
 
@@ -91,7 +92,7 @@ static void dn_slow_timer(unsigned long arg)
         * since the last successful transmission.
         */
        if (scp->keepalive && scp->keepalive_fxn && (scp->state == DN_RUN)) {
-               if ((jiffies - scp->stamp) >= scp->keepalive)
+               if (time_after_eq(jiffies, scp->stamp + scp->keepalive))
                        scp->keepalive_fxn(sk);
        }
 
index f5eede1d6cb8eb92cbf97b1b37de1362f13ac095..a585fd6352ebaf8e8bdf0e9772653857def08811 100644 (file)
@@ -12,6 +12,9 @@ config NET_DSA
 if NET_DSA
 
 # tagging formats
+config NET_DSA_TAG_BRCM
+       bool
+
 config NET_DSA_TAG_DSA
        bool
 
index 7b9fcbbeda5d0d80678ba909f76b0b30d8436a2d..da06ed1df620fc620a90ab06cfadad29ce26f3bf 100644 (file)
@@ -3,6 +3,7 @@ obj-$(CONFIG_NET_DSA) += dsa_core.o
 dsa_core-y += dsa.o slave.o
 
 # tagging formats
+dsa_core-$(CONFIG_NET_DSA_TAG_BRCM) += tag_brcm.o
 dsa_core-$(CONFIG_NET_DSA_TAG_DSA) += tag_dsa.o
 dsa_core-$(CONFIG_NET_DSA_TAG_EDSA) += tag_edsa.o
 dsa_core-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o
index 0a49632fac478f1ac17b3f0159cbdf748fe25110..61f145c445557b6aea185dc1d0c4a7504d582888 100644 (file)
@@ -144,6 +144,11 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index,
                goto out;
        }
 
+       /* Make the built-in MII bus mask match the number of ports,
+        * switch drivers can override this later
+        */
+       ds->phys_mii_mask = ds->phys_port_mask;
+
        /*
         * If the CPU connects to this switch, set the switch tree
         * tagging protocol to the preferred tagging format of this
@@ -410,6 +415,7 @@ static int dsa_of_probe(struct platform_device *pdev)
                chip_index++;
                cd = &pd->chip[chip_index];
 
+               cd->of_node = child;
                cd->mii_bus = &mdio_bus->dev;
 
                sw_addr = of_get_property(child, "reg", NULL);
@@ -431,6 +437,8 @@ static int dsa_of_probe(struct platform_device *pdev)
                        if (!port_name)
                                continue;
 
+                       cd->port_dn[port_index] = port;
+
                        cd->port_names[port_index] = kstrdup(port_name,
                                        GFP_KERNEL);
                        if (!cd->port_names[port_index]) {
@@ -608,7 +616,26 @@ static void dsa_shutdown(struct platform_device *pdev)
 {
 }
 
+static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev,
+                         struct packet_type *pt, struct net_device *orig_dev)
+{
+       struct dsa_switch_tree *dst = dev->dsa_ptr;
+
+       if (unlikely(dst == NULL)) {
+               kfree_skb(skb);
+               return 0;
+       }
+
+       return dst->ops->rcv(skb, dev, pt, orig_dev);
+}
+
+static struct packet_type dsa_pack_type __read_mostly = {
+       .type   = cpu_to_be16(ETH_P_XDSA),
+       .func   = dsa_switch_rcv,
+};
+
 static const struct of_device_id dsa_of_match_table[] = {
+       { .compatible = "brcm,bcm7445-switch-v4.0" },
        { .compatible = "marvell,dsa", },
        {}
 };
@@ -633,30 +660,15 @@ static int __init dsa_init_module(void)
        if (rc)
                return rc;
 
-#ifdef CONFIG_NET_DSA_TAG_DSA
-       dev_add_pack(&dsa_packet_type);
-#endif
-#ifdef CONFIG_NET_DSA_TAG_EDSA
-       dev_add_pack(&edsa_packet_type);
-#endif
-#ifdef CONFIG_NET_DSA_TAG_TRAILER
-       dev_add_pack(&trailer_packet_type);
-#endif
+       dev_add_pack(&dsa_pack_type);
+
        return 0;
 }
 module_init(dsa_init_module);
 
 static void __exit dsa_cleanup_module(void)
 {
-#ifdef CONFIG_NET_DSA_TAG_TRAILER
-       dev_remove_pack(&trailer_packet_type);
-#endif
-#ifdef CONFIG_NET_DSA_TAG_EDSA
-       dev_remove_pack(&edsa_packet_type);
-#endif
-#ifdef CONFIG_NET_DSA_TAG_DSA
-       dev_remove_pack(&dsa_packet_type);
-#endif
+       dev_remove_pack(&dsa_pack_type);
        platform_driver_unregister(&dsa_driver);
 }
 module_exit(dsa_cleanup_module);
index d4cf5cc747e3569f4d41855d9894b7a4fa98253d..98afed4d92baa4859615d91805a524b1bc68f25e 100644 (file)
@@ -33,6 +33,10 @@ struct dsa_slave_priv {
         * to this port.
         */
        struct phy_device       *phy;
+       phy_interface_t         phy_interface;
+       int                     old_link;
+       int                     old_pause;
+       int                     old_duplex;
 };
 
 /* dsa.c */
@@ -45,16 +49,16 @@ struct net_device *dsa_slave_create(struct dsa_switch *ds,
                                    int port, char *name);
 
 /* tag_dsa.c */
-netdev_tx_t dsa_xmit(struct sk_buff *skb, struct net_device *dev);
-extern struct packet_type dsa_packet_type;
+extern const struct dsa_device_ops dsa_netdev_ops;
 
 /* tag_edsa.c */
-netdev_tx_t edsa_xmit(struct sk_buff *skb, struct net_device *dev);
-extern struct packet_type edsa_packet_type;
+extern const struct dsa_device_ops edsa_netdev_ops;
 
 /* tag_trailer.c */
-netdev_tx_t trailer_xmit(struct sk_buff *skb, struct net_device *dev);
-extern struct packet_type trailer_packet_type;
+extern const struct dsa_device_ops trailer_netdev_ops;
+
+/* tag_brcm.c */
+extern const struct dsa_device_ops brcm_netdev_ops;
 
 
 #endif
index 45a1e34c89e0d975dd9f361a73a5617d69a10301..7333a4aebb7de2bdecf7496c681f7d4b6392f5d3 100644 (file)
@@ -12,6 +12,8 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/phy.h>
+#include <linux/of_net.h>
+#include <linux/of_mdio.h>
 #include "dsa_priv.h"
 
 /* slave mii_bus handling ***************************************************/
@@ -19,7 +21,7 @@ static int dsa_slave_phy_read(struct mii_bus *bus, int addr, int reg)
 {
        struct dsa_switch *ds = bus->priv;
 
-       if (ds->phys_port_mask & (1 << addr))
+       if (ds->phys_mii_mask & (1 << addr))
                return ds->drv->phy_read(ds, addr, reg);
 
        return 0xffff;
@@ -29,7 +31,7 @@ static int dsa_slave_phy_write(struct mii_bus *bus, int addr, int reg, u16 val)
 {
        struct dsa_switch *ds = bus->priv;
 
-       if (ds->phys_port_mask & (1 << addr))
+       if (ds->phys_mii_mask & (1 << addr))
                return ds->drv->phy_write(ds, addr, reg, val);
 
        return 0;
@@ -171,6 +173,25 @@ static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        return -EOPNOTSUPP;
 }
 
+static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct dsa_slave_priv *p = netdev_priv(dev);
+       struct dsa_switch_tree *dst = p->parent->dst;
+
+       return dst->ops->xmit(skb, dev);
+}
+
+static netdev_tx_t dsa_slave_notag_xmit(struct sk_buff *skb,
+                                       struct net_device *dev)
+{
+       struct dsa_slave_priv *p = netdev_priv(dev);
+
+       skb->dev = p->parent->dst->master_netdev;
+       dev_queue_xmit(skb);
+
+       return NETDEV_TX_OK;
+}
+
 
 /* ethtool operations *******************************************************/
 static int
@@ -293,44 +314,107 @@ static const struct ethtool_ops dsa_slave_ethtool_ops = {
        .get_sset_count         = dsa_slave_get_sset_count,
 };
 
-#ifdef CONFIG_NET_DSA_TAG_DSA
-static const struct net_device_ops dsa_netdev_ops = {
-       .ndo_init               = dsa_slave_init,
-       .ndo_open               = dsa_slave_open,
-       .ndo_stop               = dsa_slave_close,
-       .ndo_start_xmit         = dsa_xmit,
-       .ndo_change_rx_flags    = dsa_slave_change_rx_flags,
-       .ndo_set_rx_mode        = dsa_slave_set_rx_mode,
-       .ndo_set_mac_address    = dsa_slave_set_mac_address,
-       .ndo_do_ioctl           = dsa_slave_ioctl,
-};
-#endif
-#ifdef CONFIG_NET_DSA_TAG_EDSA
-static const struct net_device_ops edsa_netdev_ops = {
+static const struct net_device_ops dsa_slave_netdev_ops = {
        .ndo_init               = dsa_slave_init,
        .ndo_open               = dsa_slave_open,
        .ndo_stop               = dsa_slave_close,
-       .ndo_start_xmit         = edsa_xmit,
+       .ndo_start_xmit         = dsa_slave_xmit,
        .ndo_change_rx_flags    = dsa_slave_change_rx_flags,
        .ndo_set_rx_mode        = dsa_slave_set_rx_mode,
        .ndo_set_mac_address    = dsa_slave_set_mac_address,
        .ndo_do_ioctl           = dsa_slave_ioctl,
 };
-#endif
-#ifdef CONFIG_NET_DSA_TAG_TRAILER
-static const struct net_device_ops trailer_netdev_ops = {
-       .ndo_init               = dsa_slave_init,
-       .ndo_open               = dsa_slave_open,
-       .ndo_stop               = dsa_slave_close,
-       .ndo_start_xmit         = trailer_xmit,
-       .ndo_change_rx_flags    = dsa_slave_change_rx_flags,
-       .ndo_set_rx_mode        = dsa_slave_set_rx_mode,
-       .ndo_set_mac_address    = dsa_slave_set_mac_address,
-       .ndo_do_ioctl           = dsa_slave_ioctl,
+
+static const struct dsa_device_ops notag_netdev_ops = {
+       .xmit   = dsa_slave_notag_xmit,
+       .rcv    = NULL,
 };
-#endif
+
+static void dsa_slave_adjust_link(struct net_device *dev)
+{
+       struct dsa_slave_priv *p = netdev_priv(dev);
+       struct dsa_switch *ds = p->parent;
+       unsigned int status_changed = 0;
+
+       if (p->old_link != p->phy->link) {
+               status_changed = 1;
+               p->old_link = p->phy->link;
+       }
+
+       if (p->old_duplex != p->phy->duplex) {
+               status_changed = 1;
+               p->old_duplex = p->phy->duplex;
+       }
+
+       if (p->old_pause != p->phy->pause) {
+               status_changed = 1;
+               p->old_pause = p->phy->pause;
+       }
+
+       if (ds->drv->adjust_link && status_changed)
+               ds->drv->adjust_link(ds, p->port, p->phy);
+
+       if (status_changed)
+               phy_print_status(p->phy);
+}
+
+static int dsa_slave_fixed_link_update(struct net_device *dev,
+                                      struct fixed_phy_status *status)
+{
+       struct dsa_slave_priv *p = netdev_priv(dev);
+       struct dsa_switch *ds = p->parent;
+
+       if (ds->drv->fixed_link_update)
+               ds->drv->fixed_link_update(ds, p->port, status);
+
+       return 0;
+}
 
 /* slave device setup *******************************************************/
+static void dsa_slave_phy_setup(struct dsa_slave_priv *p,
+                               struct net_device *slave_dev)
+{
+       struct dsa_switch *ds = p->parent;
+       struct dsa_chip_data *cd = ds->pd;
+       struct device_node *phy_dn, *port_dn;
+       bool phy_is_fixed = false;
+       int ret;
+
+       port_dn = cd->port_dn[p->port];
+       p->phy_interface = of_get_phy_mode(port_dn);
+
+       phy_dn = of_parse_phandle(port_dn, "phy-handle", 0);
+       if (of_phy_is_fixed_link(port_dn)) {
+               /* In the case of a fixed PHY, the DT node associated
+                * to the fixed PHY is the Port DT node
+                */
+               ret = of_phy_register_fixed_link(port_dn);
+               if (ret) {
+                       pr_err("failed to register fixed PHY\n");
+                       return;
+               }
+               phy_is_fixed = true;
+               phy_dn = port_dn;
+       }
+
+       if (phy_dn)
+               p->phy = of_phy_connect(slave_dev, phy_dn,
+                                       dsa_slave_adjust_link, 0,
+                                       p->phy_interface);
+
+       if (p->phy && phy_is_fixed)
+               fixed_phy_set_link_update(p->phy, dsa_slave_fixed_link_update);
+
+       /* We could not connect to a designated PHY, so use the switch internal
+        * MDIO bus instead
+        */
+       if (!p->phy)
+               p->phy = ds->slave_mii_bus->phy_map[p->port];
+       else
+               pr_info("attached PHY at address %d [%s]\n",
+                       p->phy->addr, p->phy->drv->name);
+}
+
 struct net_device *
 dsa_slave_create(struct dsa_switch *ds, struct device *parent,
                 int port, char *name)
@@ -349,35 +433,48 @@ dsa_slave_create(struct dsa_switch *ds, struct device *parent,
        slave_dev->ethtool_ops = &dsa_slave_ethtool_ops;
        eth_hw_addr_inherit(slave_dev, master);
        slave_dev->tx_queue_len = 0;
+       slave_dev->netdev_ops = &dsa_slave_netdev_ops;
 
        switch (ds->dst->tag_protocol) {
 #ifdef CONFIG_NET_DSA_TAG_DSA
        case htons(ETH_P_DSA):
-               slave_dev->netdev_ops = &dsa_netdev_ops;
+               ds->dst->ops = &dsa_netdev_ops;
                break;
 #endif
 #ifdef CONFIG_NET_DSA_TAG_EDSA
        case htons(ETH_P_EDSA):
-               slave_dev->netdev_ops = &edsa_netdev_ops;
+               ds->dst->ops = &edsa_netdev_ops;
                break;
 #endif
 #ifdef CONFIG_NET_DSA_TAG_TRAILER
        case htons(ETH_P_TRAILER):
-               slave_dev->netdev_ops = &trailer_netdev_ops;
+               ds->dst->ops = &trailer_netdev_ops;
+               break;
+#endif
+#ifdef CONFIG_NET_DSA_TAG_BRCM
+       case htons(ETH_P_BRCMTAG):
+               ds->dst->ops = &brcm_netdev_ops;
                break;
 #endif
        default:
-               BUG();
+               ds->dst->ops = &notag_netdev_ops;
+               break;
        }
 
        SET_NETDEV_DEV(slave_dev, parent);
+       slave_dev->dev.of_node = ds->pd->port_dn[port];
        slave_dev->vlan_features = master->vlan_features;
 
        p = netdev_priv(slave_dev);
        p->dev = slave_dev;
        p->parent = ds;
        p->port = port;
-       p->phy = ds->slave_mii_bus->phy_map[port];
+
+       p->old_pause = -1;
+       p->old_link = -1;
+       p->old_duplex = -1;
+
+       dsa_slave_phy_setup(p, slave_dev);
 
        ret = register_netdev(slave_dev);
        if (ret) {
diff --git a/net/dsa/tag_brcm.c b/net/dsa/tag_brcm.c
new file mode 100644 (file)
index 0000000..e0b759e
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Broadcom tag 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/etherdevice.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <linux/slab.h>
+#include "dsa_priv.h"
+
+/* This tag length is 4 bytes, older ones were 6 bytes, we do not
+ * handle them
+ */
+#define BRCM_TAG_LEN   4
+
+/* Tag is constructed and desconstructed using byte by byte access
+ * because the tag is placed after the MAC Source Address, which does
+ * not make it 4-bytes aligned, so this might cause unaligned accesses
+ * on most systems where this is used.
+ */
+
+/* Ingress and egress opcodes */
+#define BRCM_OPCODE_SHIFT      5
+#define BRCM_OPCODE_MASK       0x7
+
+/* Ingress fields */
+/* 1st byte in the tag */
+#define BRCM_IG_TC_SHIFT       2
+#define BRCM_IG_TC_MASK                0x7
+/* 2nd byte in the tag */
+#define BRCM_IG_TE_MASK                0x3
+#define BRCM_IG_TS_SHIFT       7
+/* 3rd byte in the tag */
+#define BRCM_IG_DSTMAP2_MASK   1
+#define BRCM_IG_DSTMAP1_MASK   0xff
+
+/* Egress fields */
+
+/* 2nd byte in the tag */
+#define BRCM_EG_CID_MASK       0xff
+
+/* 3rd byte in the tag */
+#define BRCM_EG_RC_MASK                0xff
+#define  BRCM_EG_RC_RSVD       (3 << 6)
+#define  BRCM_EG_RC_EXCEPTION  (1 << 5)
+#define  BRCM_EG_RC_PROT_SNOOP (1 << 4)
+#define  BRCM_EG_RC_PROT_TERM  (1 << 3)
+#define  BRCM_EG_RC_SWITCH     (1 << 2)
+#define  BRCM_EG_RC_MAC_LEARN  (1 << 1)
+#define  BRCM_EG_RC_MIRROR     (1 << 0)
+#define BRCM_EG_TC_SHIFT       5
+#define BRCM_EG_TC_MASK                0x7
+#define BRCM_EG_PID_MASK       0x1f
+
+static netdev_tx_t brcm_tag_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct dsa_slave_priv *p = netdev_priv(dev);
+       u8 *brcm_tag;
+
+       dev->stats.tx_packets++;
+       dev->stats.tx_bytes += skb->len;
+
+       if (skb_cow_head(skb, BRCM_TAG_LEN) < 0)
+               goto out_free;
+
+       skb_push(skb, BRCM_TAG_LEN);
+
+       memmove(skb->data, skb->data + BRCM_TAG_LEN, 2 * ETH_ALEN);
+
+       /* Build the tag after the MAC Source Address */
+       brcm_tag = skb->data + 2 * ETH_ALEN;
+
+       /* Set the ingress opcode, traffic class, tag enforcment is
+        * deprecated
+        */
+       brcm_tag[0] = (1 << BRCM_OPCODE_SHIFT) |
+                       ((skb->priority << BRCM_IG_TC_SHIFT) & BRCM_IG_TC_MASK);
+       brcm_tag[1] = 0;
+       brcm_tag[2] = 0;
+       if (p->port == 8)
+               brcm_tag[2] = BRCM_IG_DSTMAP2_MASK;
+       brcm_tag[3] = (1 << p->port) & BRCM_IG_DSTMAP1_MASK;
+
+       /* Queue the SKB for transmission on the parent interface, but
+        * do not modify its EtherType
+        */
+       skb->protocol = htons(ETH_P_BRCMTAG);
+       skb->dev = p->parent->dst->master_netdev;
+       dev_queue_xmit(skb);
+
+       return NETDEV_TX_OK;
+
+out_free:
+       kfree_skb(skb);
+       return NETDEV_TX_OK;
+}
+
+static int brcm_tag_rcv(struct sk_buff *skb, struct net_device *dev,
+                       struct packet_type *pt, struct net_device *orig_dev)
+{
+       struct dsa_switch_tree *dst = dev->dsa_ptr;
+       struct dsa_switch *ds;
+       int source_port;
+       u8 *brcm_tag;
+
+       if (unlikely(dst == NULL))
+               goto out_drop;
+
+       ds = dst->ds[0];
+
+       skb = skb_unshare(skb, GFP_ATOMIC);
+       if (skb == NULL)
+               goto out;
+
+       if (unlikely(!pskb_may_pull(skb, BRCM_TAG_LEN)))
+               goto out_drop;
+
+       /* skb->data points to the EtherType, the tag is right before it */
+       brcm_tag = skb->data - 2;
+
+       /* The opcode should never be different than 0b000 */
+       if (unlikely((brcm_tag[0] >> BRCM_OPCODE_SHIFT) & BRCM_OPCODE_MASK))
+               goto out_drop;
+
+       /* We should never see a reserved reason code without knowing how to
+        * handle it
+        */
+       WARN_ON(brcm_tag[2] & BRCM_EG_RC_RSVD);
+
+       /* Locate which port this is coming from */
+       source_port = brcm_tag[3] & BRCM_EG_PID_MASK;
+
+       /* Validate port against switch setup, either the port is totally */
+       if (source_port >= DSA_MAX_PORTS || ds->ports[source_port] == NULL)
+               goto out_drop;
+
+       /* Remove Broadcom tag and update checksum */
+       skb_pull_rcsum(skb, BRCM_TAG_LEN);
+
+       /* Move the Ethernet DA and SA */
+       memmove(skb->data - ETH_HLEN,
+               skb->data - ETH_HLEN - BRCM_TAG_LEN,
+               2 * ETH_ALEN);
+
+       skb_push(skb, ETH_HLEN);
+       skb->pkt_type = PACKET_HOST;
+       skb->dev = ds->ports[source_port];
+       skb->protocol = eth_type_trans(skb, skb->dev);
+
+       skb->dev->stats.rx_packets++;
+       skb->dev->stats.rx_bytes += skb->len;
+
+       netif_receive_skb(skb);
+
+       return 0;
+
+out_drop:
+       kfree_skb(skb);
+out:
+       return 0;
+}
+
+const struct dsa_device_ops brcm_netdev_ops = {
+       .xmit   = brcm_tag_xmit,
+       .rcv    = brcm_tag_rcv,
+};
index cacce1e22f9caa029c2374cd93c2e071932f365c..d7dbc5bda5c0f587571c8d15d37c8705c493bfb4 100644 (file)
@@ -16,7 +16,7 @@
 
 #define DSA_HLEN       4
 
-netdev_tx_t dsa_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t dsa_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct dsa_slave_priv *p = netdev_priv(dev);
        u8 *dsa_header;
@@ -186,7 +186,7 @@ out:
        return 0;
 }
 
-struct packet_type dsa_packet_type __read_mostly = {
-       .type   = cpu_to_be16(ETH_P_DSA),
-       .func   = dsa_rcv,
+const struct dsa_device_ops dsa_netdev_ops = {
+       .xmit   = dsa_xmit,
+       .rcv    = dsa_rcv,
 };
index e70c43c25e64c9310d3d5a61b407d8eeb76402d2..6b30abe89183f4de5e8ff7f105be1b593e749d79 100644 (file)
@@ -17,7 +17,7 @@
 #define DSA_HLEN       4
 #define EDSA_HLEN      8
 
-netdev_tx_t edsa_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t edsa_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct dsa_slave_priv *p = netdev_priv(dev);
        u8 *edsa_header;
@@ -205,7 +205,7 @@ out:
        return 0;
 }
 
-struct packet_type edsa_packet_type __read_mostly = {
-       .type   = cpu_to_be16(ETH_P_EDSA),
-       .func   = edsa_rcv,
+const struct dsa_device_ops edsa_netdev_ops = {
+       .xmit   = edsa_xmit,
+       .rcv    = edsa_rcv,
 };
index 94bc260d015d11f1a321ca3f3876c7b901716302..5fe9444842c573b7b251266a166719887068c739 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/slab.h>
 #include "dsa_priv.h"
 
-netdev_tx_t trailer_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t trailer_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct dsa_slave_priv *p = netdev_priv(dev);
        struct sk_buff *nskb;
@@ -114,7 +114,7 @@ out:
        return 0;
 }
 
-struct packet_type trailer_packet_type __read_mostly = {
-       .type   = cpu_to_be16(ETH_P_TRAILER),
-       .func   = trailer_rcv,
+const struct dsa_device_ops trailer_netdev_ops = {
+       .xmit   = trailer_xmit,
+       .rcv    = trailer_rcv,
 };
index f405e05924078b2d30f45139cd698843a16256da..33a140e1583449bcf2816bb91792e810f7c1734f 100644 (file)
@@ -145,6 +145,33 @@ int eth_rebuild_header(struct sk_buff *skb)
 }
 EXPORT_SYMBOL(eth_rebuild_header);
 
+/**
+ * eth_get_headlen - determine the the length of header for an ethernet frame
+ * @data: pointer to start of frame
+ * @len: total length of frame
+ *
+ * Make a best effort attempt to pull the length for all of the headers for
+ * a given frame in a linear buffer.
+ */
+u32 eth_get_headlen(void *data, unsigned int len)
+{
+       const struct ethhdr *eth = (const struct ethhdr *)data;
+       struct flow_keys keys;
+
+       /* this should never happen, but better safe than sorry */
+       if (len < sizeof(*eth))
+               return len;
+
+       /* parse any remaining L2/L3 headers, check for L4 */
+       if (!__skb_flow_dissect(NULL, &keys, data,
+                               eth->h_proto, sizeof(*eth), len))
+               return max_t(u32, keys.thoff, sizeof(*eth));
+
+       /* parse for any L4 headers */
+       return min_t(u32, __skb_get_poff(NULL, data, &keys, len), len);
+}
+EXPORT_SYMBOL(eth_get_headlen);
+
 /**
  * eth_type_trans - determine the packet's protocol ID.
  * @skb: received socket data
@@ -181,11 +208,8 @@ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev)
         * variants has been configured on the receiving interface,
         * and if so, set skb->protocol without looking at the packet.
         */
-       if (unlikely(netdev_uses_dsa_tags(dev)))
-               return htons(ETH_P_DSA);
-
-       if (unlikely(netdev_uses_trailer_tags(dev)))
-               return htons(ETH_P_TRAILER);
+       if (unlikely(netdev_uses_dsa(dev)))
+               return htons(ETH_P_XDSA);
 
        if (likely(ntohs(eth->h_proto) >= ETH_P_802_3_MIN))
                return eth->h_proto;
index 016b77ee88f0e2f1394c0456f67e9e01ec190d9f..5e788cdc499a34c5a156e65e4afeda2927587118 100644 (file)
@@ -77,14 +77,6 @@ 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)
@@ -246,7 +238,7 @@ lowpan_alloc_frag(struct sk_buff *skb, int size,
                        return ERR_PTR(-rc);
                }
        } else {
-               frag = ERR_PTR(ENOMEM);
+               frag = ERR_PTR(-ENOMEM);
        }
 
        return frag;
@@ -437,7 +429,7 @@ static void lowpan_setup(struct net_device *dev)
        /* 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->mtu                = IPV6_MIN_MTU;
        dev->tx_queue_len       = 0;
        dev->flags              = IFF_BROADCAST | IFF_MULTICAST;
        dev->watchdog_timeo     = 0;
index ffec6ce510056960bb92d6ef0c3e44bc9493676f..32755cb7e64e3c02f77c85bdad6982d31311bcc5 100644 (file)
@@ -355,8 +355,6 @@ int lowpan_frag_rcv(struct sk_buff *skb, const u8 frag_type)
        struct net *net = dev_net(skb->dev);
        struct lowpan_frag_info *frag_info = lowpan_cb(skb);
        struct ieee802154_addr source, dest;
-       struct netns_ieee802154_lowpan *ieee802154_lowpan =
-               net_ieee802154_lowpan(net);
        int err;
 
        source = mac_cb(skb)->source;
@@ -366,8 +364,10 @@ int lowpan_frag_rcv(struct sk_buff *skb, const u8 frag_type)
        if (err < 0)
                goto err;
 
-       if (frag_info->d_size > ieee802154_lowpan->max_dsize)
+       if (frag_info->d_size > IPV6_MIN_MTU) {
+               net_warn_ratelimited("lowpan_frag_rcv: datagram size exceeds MTU\n");
                goto err;
+       }
 
        fq = fq_find(net, frag_info, &source, &dest);
        if (fq != NULL) {
@@ -415,13 +415,6 @@ static struct ctl_table lowpan_frags_ns_ctl_table[] = {
                .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
-       },
        { }
 };
 
@@ -458,7 +451,6 @@ static int __net_init lowpan_frags_ns_sysctl_register(struct net *net)
                table[1].data = &ieee802154_lowpan->frags.low_thresh;
                table[1].extra2 = &ieee802154_lowpan->frags.high_thresh;
                table[2].data = &ieee802154_lowpan->frags.timeout;
-               table[3].data = &ieee802154_lowpan->max_dsize;
 
                /* Don't export sysctls to unprivileged users */
                if (net->user_ns != &init_user_ns)
@@ -533,7 +525,6 @@ static int __net_init lowpan_frags_init_net(struct net *net)
        ieee802154_lowpan->frags.high_thresh = IPV6_FRAG_HIGH_THRESH;
        ieee802154_lowpan->frags.low_thresh = IPV6_FRAG_LOW_THRESH;
        ieee802154_lowpan->frags.timeout = IPV6_FRAG_TIMEOUT;
-       ieee802154_lowpan->max_dsize = 0xFFFF;
 
        inet_frags_init_net(&ieee802154_lowpan->frags);
 
index d156b3c5f3631f169f179bfdd534b69ce5070b82..72011cc4c13bb1301e193a65386dafb608f5c78d 100644 (file)
@@ -418,10 +418,6 @@ int inet_release(struct socket *sock)
 }
 EXPORT_SYMBOL(inet_release);
 
-/* It is off by default, see below. */
-int sysctl_ip_nonlocal_bind __read_mostly;
-EXPORT_SYMBOL(sysctl_ip_nonlocal_bind);
-
 int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 {
        struct sockaddr_in *addr = (struct sockaddr_in *)uaddr;
@@ -461,7 +457,7 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
         *  is temporarily down)
         */
        err = -EADDRNOTAVAIL;
-       if (!sysctl_ip_nonlocal_bind &&
+       if (!net->ipv4.sysctl_ip_nonlocal_bind &&
            !(inet->freebind || inet->transparent) &&
            addr->sin_addr.s_addr != htonl(INADDR_ANY) &&
            chk_addr_ret != RTN_LOCAL &&
@@ -1670,6 +1666,8 @@ static const struct net_offload ipip_offload = {
        .callbacks = {
                .gso_send_check = inet_gso_send_check,
                .gso_segment    = inet_gso_segment,
+               .gro_receive    = inet_gro_receive,
+               .gro_complete   = inet_gro_complete,
        },
 };
 
index 255aa9946fe785a2577fbdb23560288599c1ba0a..23104a3f29245abeb682089185bd103ae4794cb2 100644 (file)
@@ -243,7 +243,7 @@ static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
                                 u8 tos, int oif, struct net_device *dev,
                                 int rpf, struct in_device *idev, u32 *itag)
 {
-       int ret, no_addr, accept_local;
+       int ret, no_addr;
        struct fib_result res;
        struct flowi4 fl4;
        struct net *net;
@@ -258,16 +258,17 @@ static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
 
        no_addr = idev->ifa_list == NULL;
 
-       accept_local = IN_DEV_ACCEPT_LOCAL(idev);
        fl4.flowi4_mark = IN_DEV_SRC_VMARK(idev) ? skb->mark : 0;
 
        net = dev_net(dev);
        if (fib_lookup(net, &fl4, &res))
                goto last_resort;
-       if (res.type != RTN_UNICAST) {
-               if (res.type != RTN_LOCAL || !accept_local)
-                       goto e_inval;
-       }
+       if (res.type != RTN_UNICAST &&
+           (res.type != RTN_LOCAL || !IN_DEV_ACCEPT_LOCAL(idev)))
+               goto e_inval;
+       if (!rpf && !fib_num_tclassid_users(dev_net(dev)) &&
+           (dev->ifindex != oif || !IN_DEV_TX_REDIRECTS(idev)))
+               goto last_resort;
        fib_combine_itag(itag, &res);
        dev_match = false;
 
@@ -321,6 +322,7 @@ int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
        int r = secpath_exists(skb) ? 0 : IN_DEV_RPFILTER(idev);
 
        if (!r && !fib_num_tclassid_users(dev_net(dev)) &&
+           IN_DEV_ACCEPT_LOCAL(idev) &&
            (dev->ifindex != oif || !IN_DEV_TX_REDIRECTS(idev))) {
                *itag = 0;
                return 0;
index b10cd43a4722730205272d7822d699bc49ea71d3..5b6efb3d2308b0b40b22da7274ad611c4f3d0158 100644 (file)
@@ -157,9 +157,12 @@ static void rt_fibinfo_free(struct rtable __rcu **rtp)
 
 static void free_nh_exceptions(struct fib_nh *nh)
 {
-       struct fnhe_hash_bucket *hash = nh->nh_exceptions;
+       struct fnhe_hash_bucket *hash;
        int i;
 
+       hash = rcu_dereference_protected(nh->nh_exceptions, 1);
+       if (!hash)
+               return;
        for (i = 0; i < FNHE_HASH_SIZE; i++) {
                struct fib_nh_exception *fnhe;
 
@@ -205,8 +208,7 @@ static void free_fib_info_rcu(struct rcu_head *head)
        change_nexthops(fi) {
                if (nexthop_nh->nh_dev)
                        dev_put(nexthop_nh->nh_dev);
-               if (nexthop_nh->nh_exceptions)
-                       free_nh_exceptions(nexthop_nh);
+               free_nh_exceptions(nexthop_nh);
                rt_fibinfo_free_cpus(nexthop_nh->nh_pcpu_rth_output);
                rt_fibinfo_free(&nexthop_nh->nh_rth_input);
        } endfor_nexthops(fi);
index 0485bf7f8f030d59bc6e9ee499051e99d9ab53d6..4a7b5b2a1ce3ddbd79e9282051020a4509dd7fe5 100644 (file)
@@ -98,7 +98,6 @@ EXPORT_SYMBOL_GPL(gre_build_header);
 static int parse_gre_header(struct sk_buff *skb, struct tnl_ptk_info *tpi,
                            bool *csum_err)
 {
-       unsigned int ip_hlen = ip_hdrlen(skb);
        const struct gre_base_hdr *greh;
        __be32 *options;
        int hdr_len;
@@ -106,7 +105,7 @@ static int parse_gre_header(struct sk_buff *skb, struct tnl_ptk_info *tpi,
        if (unlikely(!pskb_may_pull(skb, sizeof(struct gre_base_hdr))))
                return -EINVAL;
 
-       greh = (struct gre_base_hdr *)(skb_network_header(skb) + ip_hlen);
+       greh = (struct gre_base_hdr *)skb_transport_header(skb);
        if (unlikely(greh->flags & (GRE_VERSION | GRE_ROUTING)))
                return -EINVAL;
 
@@ -116,7 +115,7 @@ static int parse_gre_header(struct sk_buff *skb, struct tnl_ptk_info *tpi,
        if (!pskb_may_pull(skb, hdr_len))
                return -EINVAL;
 
-       greh = (struct gre_base_hdr *)(skb_network_header(skb) + ip_hlen);
+       greh = (struct gre_base_hdr *)skb_transport_header(skb);
        tpi->proto = greh->protocol;
 
        options = (__be32 *)(greh + 1);
@@ -125,6 +124,10 @@ static int parse_gre_header(struct sk_buff *skb, struct tnl_ptk_info *tpi,
                        *csum_err = true;
                        return -EINVAL;
                }
+
+               skb_checksum_try_convert(skb, IPPROTO_GRE, 0,
+                                        null_compute_pseudo);
+
                options++;
        }
 
index 6556263c8fa52330efd6e4d9d4f5b491ac9dbe41..d3fe2ac05167230985e44a4cfc2150b279717dc0 100644 (file)
@@ -119,28 +119,6 @@ out:
        return segs;
 }
 
-/* Compute the whole skb csum in s/w and store it, then verify GRO csum
- * starting from gro_offset.
- */
-static __sum16 gro_skb_checksum(struct sk_buff *skb)
-{
-       __sum16 sum;
-
-       skb->csum = skb_checksum(skb, 0, skb->len, 0);
-       NAPI_GRO_CB(skb)->csum = csum_sub(skb->csum,
-               csum_partial(skb->data, skb_gro_offset(skb), 0));
-       sum = csum_fold(NAPI_GRO_CB(skb)->csum);
-       if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE)) {
-               if (unlikely(!sum) && !skb->csum_complete_sw)
-                       netdev_rx_csum_fault(skb->dev);
-       } else {
-               skb->ip_summed = CHECKSUM_COMPLETE;
-               skb->csum_complete_sw = 1;
-       }
-
-       return sum;
-}
-
 static struct sk_buff **gre_gro_receive(struct sk_buff **head,
                                        struct sk_buff *skb)
 {
@@ -192,22 +170,16 @@ static struct sk_buff **gre_gro_receive(struct sk_buff **head,
                if (unlikely(!greh))
                        goto out_unlock;
        }
-       if (greh->flags & GRE_CSUM) { /* Need to verify GRE csum first */
-               __sum16 csum = 0;
-
-               if (skb->ip_summed == CHECKSUM_COMPLETE)
-                       csum = csum_fold(NAPI_GRO_CB(skb)->csum);
-               /* Don't trust csum error calculated/reported by h/w */
-               if (skb->ip_summed == CHECKSUM_NONE || csum != 0)
-                       csum = gro_skb_checksum(skb);
-
-               /* GRE CSUM is the 1's complement of the 1's complement sum
-                * of the GRE hdr plus payload so it should add up to 0xffff
-                * (and 0 after csum_fold()) just like the IPv4 hdr csum.
-                */
-               if (csum)
+
+       /* Don't bother verifying checksum if we're going to flush anyway. */
+       if ((greh->flags & GRE_CSUM) && !NAPI_GRO_CB(skb)->flush) {
+               if (skb_gro_checksum_simple_validate(skb))
                        goto out_unlock;
+
+               skb_gro_checksum_try_convert(skb, IPPROTO_GRE, 0,
+                                            null_compute_pseudo);
        }
+
        flush = 0;
 
        for (p = *head; p; p = p->next) {
index f10eab462282b1afa80bcc3e7bac7f862ab9709f..4146153d875d3ea9a35fa1b53ac01f76bf420e45 100644 (file)
 #define IGMP_V2_Unsolicited_Report_Interval    (10*HZ)
 #define IGMP_V3_Unsolicited_Report_Interval    (1*HZ)
 #define IGMP_Query_Response_Interval           (10*HZ)
-#define IGMP_Unsolicited_Report_Count          2
+#define IGMP_Query_Robustness_Variable         2
 
 
 #define IGMP_Initial_Report_Delay              (1)
@@ -756,8 +756,7 @@ static void igmp_ifc_event(struct in_device *in_dev)
 {
        if (IGMP_V1_SEEN(in_dev) || IGMP_V2_SEEN(in_dev))
                return;
-       in_dev->mr_ifc_count = in_dev->mr_qrv ? in_dev->mr_qrv :
-               IGMP_Unsolicited_Report_Count;
+       in_dev->mr_ifc_count = in_dev->mr_qrv ?: sysctl_igmp_qrv;
        igmp_ifc_start_timer(in_dev, 1);
 }
 
@@ -1086,8 +1085,7 @@ static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im)
        pmc->interface = im->interface;
        in_dev_hold(in_dev);
        pmc->multiaddr = im->multiaddr;
-       pmc->crcount = in_dev->mr_qrv ? in_dev->mr_qrv :
-               IGMP_Unsolicited_Report_Count;
+       pmc->crcount = in_dev->mr_qrv ?: sysctl_igmp_qrv;
        pmc->sfmode = im->sfmode;
        if (pmc->sfmode == MCAST_INCLUDE) {
                struct ip_sf_list *psf;
@@ -1226,8 +1224,7 @@ static void igmp_group_added(struct ip_mc_list *im)
        }
        /* else, v3 */
 
-       im->crcount = in_dev->mr_qrv ? in_dev->mr_qrv :
-               IGMP_Unsolicited_Report_Count;
+       im->crcount = in_dev->mr_qrv ?: sysctl_igmp_qrv;
        igmp_ifc_event(in_dev);
 #endif
 }
@@ -1322,7 +1319,7 @@ void ip_mc_inc_group(struct in_device *in_dev, __be32 addr)
        spin_lock_init(&im->lock);
 #ifdef CONFIG_IP_MULTICAST
        setup_timer(&im->timer, igmp_timer_expire, (unsigned long)im);
-       im->unsolicit_count = IGMP_Unsolicited_Report_Count;
+       im->unsolicit_count = sysctl_igmp_qrv;
 #endif
 
        im->next_rcu = in_dev->mc_list;
@@ -1460,7 +1457,7 @@ void ip_mc_init_dev(struct in_device *in_dev)
                        (unsigned long)in_dev);
        setup_timer(&in_dev->mr_ifc_timer, igmp_ifc_timer_expire,
                        (unsigned long)in_dev);
-       in_dev->mr_qrv = IGMP_Unsolicited_Report_Count;
+       in_dev->mr_qrv = sysctl_igmp_qrv;
 #endif
 
        spin_lock_init(&in_dev->mc_tomb_lock);
@@ -1474,6 +1471,9 @@ void ip_mc_up(struct in_device *in_dev)
 
        ASSERT_RTNL();
 
+#ifdef CONFIG_IP_MULTICAST
+       in_dev->mr_qrv = sysctl_igmp_qrv;
+#endif
        ip_mc_inc_group(in_dev, IGMP_ALL_HOSTS);
 
        for_each_pmc_rtnl(in_dev, pmc)
@@ -1540,7 +1540,9 @@ static struct in_device *ip_mc_find_dev(struct net *net, struct ip_mreqn *imr)
  */
 int sysctl_igmp_max_memberships __read_mostly = IP_MAX_MEMBERSHIPS;
 int sysctl_igmp_max_msf __read_mostly = IP_MAX_MSF;
-
+#ifdef CONFIG_IP_MULTICAST
+int sysctl_igmp_qrv __read_mostly = IGMP_Query_Robustness_Variable;
+#endif
 
 static int ip_mc_del1_src(struct ip_mc_list *pmc, int sfmode,
        __be32 *psfsrc)
@@ -1575,8 +1577,7 @@ static int ip_mc_del1_src(struct ip_mc_list *pmc, int sfmode,
 #ifdef CONFIG_IP_MULTICAST
                if (psf->sf_oldin &&
                    !IGMP_V1_SEEN(in_dev) && !IGMP_V2_SEEN(in_dev)) {
-                       psf->sf_crcount = in_dev->mr_qrv ? in_dev->mr_qrv :
-                               IGMP_Unsolicited_Report_Count;
+                       psf->sf_crcount = in_dev->mr_qrv ?: sysctl_igmp_qrv;
                        psf->sf_next = pmc->tomb;
                        pmc->tomb = psf;
                        rv = 1;
@@ -1639,8 +1640,7 @@ static int ip_mc_del_src(struct in_device *in_dev, __be32 *pmca, int sfmode,
                /* filter mode change */
                pmc->sfmode = MCAST_INCLUDE;
 #ifdef CONFIG_IP_MULTICAST
-               pmc->crcount = in_dev->mr_qrv ? in_dev->mr_qrv :
-                       IGMP_Unsolicited_Report_Count;
+               pmc->crcount = in_dev->mr_qrv ?: sysctl_igmp_qrv;
                in_dev->mr_ifc_count = pmc->crcount;
                for (psf = pmc->sources; psf; psf = psf->sf_next)
                        psf->sf_crcount = 0;
@@ -1818,8 +1818,7 @@ static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode,
 #ifdef CONFIG_IP_MULTICAST
                /* else no filters; keep old mode for reports */
 
-               pmc->crcount = in_dev->mr_qrv ? in_dev->mr_qrv :
-                       IGMP_Unsolicited_Report_Count;
+               pmc->crcount = in_dev->mr_qrv ?: sysctl_igmp_qrv;
                in_dev->mr_ifc_count = pmc->crcount;
                for (psf = pmc->sources; psf; psf = psf->sf_next)
                        psf->sf_crcount = 0;
@@ -2539,7 +2538,7 @@ static int igmp_mc_seq_show(struct seq_file *seq, void *v)
                querier = "NONE";
 #endif
 
-               if (rcu_dereference(state->in_dev->mc_list) == im) {
+               if (rcu_access_pointer(state->in_dev->mc_list) == im) {
                        seq_printf(seq, "%d\t%-10s: %5d %7s\n",
                                   state->dev->ifindex, state->dev->name, state->in_dev->mc_count, querier);
                }
index 43116e8c8e1323cdd8d902c5b88e42187c8df991..9111a4e221557173df0ce08e95632ee059d00b61 100644 (file)
@@ -229,7 +229,7 @@ begin:
                        }
                } else if (score == hiscore && reuseport) {
                        matches++;
-                       if (((u64)phash * matches) >> 32 == 0)
+                       if (reciprocal_scale(phash, matches) == 0)
                                result = sk;
                        phash = next_pseudo_random32(phash);
                }
index bd5f5928167dbd44c72fbd1a5eefd475bd29f260..241afd743d2ccfda93bfb42b928020f2d9dc0486 100644 (file)
@@ -72,29 +72,10 @@ void inet_peer_base_init(struct inet_peer_base *bp)
 {
        bp->root = peer_avl_empty_rcu;
        seqlock_init(&bp->lock);
-       bp->flush_seq = ~0U;
        bp->total = 0;
 }
 EXPORT_SYMBOL_GPL(inet_peer_base_init);
 
-static atomic_t v4_seq = ATOMIC_INIT(0);
-static atomic_t v6_seq = ATOMIC_INIT(0);
-
-static atomic_t *inetpeer_seq_ptr(int family)
-{
-       return (family == AF_INET ? &v4_seq : &v6_seq);
-}
-
-static inline void flush_check(struct inet_peer_base *base, int family)
-{
-       atomic_t *fp = inetpeer_seq_ptr(family);
-
-       if (unlikely(base->flush_seq != atomic_read(fp))) {
-               inetpeer_invalidate_tree(base);
-               base->flush_seq = atomic_read(fp);
-       }
-}
-
 #define PEER_MAXDEPTH 40 /* sufficient for about 2^27 nodes */
 
 /* Exported for sysctl_net_ipv4.  */
@@ -444,8 +425,6 @@ struct inet_peer *inet_getpeer(struct inet_peer_base *base,
        unsigned int sequence;
        int invalidated, gccnt = 0;
 
-       flush_check(base, daddr->family);
-
        /* Attempt a lockless lookup first.
         * Because of a concurrent writer, we might not find an existing entry.
         */
index 5cb830c78990a8642aed4df591b7109260de685c..c373a9ad45556815d1d95f4faf71b8f8a3f61996 100644 (file)
@@ -303,7 +303,7 @@ int ip_ra_control(struct sock *sk, unsigned char on,
                        }
                        /* dont let ip_call_ra_chain() use sk again */
                        ra->sk = NULL;
-                       rcu_assign_pointer(*rap, ra->next);
+                       RCU_INIT_POINTER(*rap, ra->next);
                        spin_unlock_bh(&ip_ra_lock);
 
                        if (ra->destructor)
@@ -325,7 +325,7 @@ int ip_ra_control(struct sock *sk, unsigned char on,
        new_ra->sk = sk;
        new_ra->destructor = destructor;
 
-       new_ra->next = ra;
+       RCU_INIT_POINTER(new_ra->next, ra);
        rcu_assign_pointer(*rap, new_ra);
        sock_hold(sk);
        spin_unlock_bh(&ip_ra_lock);
@@ -405,7 +405,7 @@ void ip_local_error(struct sock *sk, int err, __be32 daddr, __be16 port, u32 inf
 int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
 {
        struct sock_exterr_skb *serr;
-       struct sk_buff *skb, *skb2;
+       struct sk_buff *skb;
        DECLARE_SOCKADDR(struct sockaddr_in *, sin, msg->msg_name);
        struct {
                struct sock_extended_err ee;
@@ -415,7 +415,7 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
        int copied;
 
        err = -EAGAIN;
-       skb = skb_dequeue(&sk->sk_error_queue);
+       skb = sock_dequeue_err_skb(sk);
        if (skb == NULL)
                goto out;
 
@@ -462,17 +462,6 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
        msg->msg_flags |= MSG_ERRQUEUE;
        err = copied;
 
-       /* Reset and regenerate socket error */
-       spin_lock_bh(&sk->sk_error_queue.lock);
-       sk->sk_err = 0;
-       skb2 = skb_peek(&sk->sk_error_queue);
-       if (skb2 != NULL) {
-               sk->sk_err = SKB_EXT_ERR(skb2)->ee.ee_errno;
-               spin_unlock_bh(&sk->sk_error_queue.lock);
-               sk->sk_error_report(sk);
-       } else
-               spin_unlock_bh(&sk->sk_error_queue.lock);
-
 out_free_skb:
        kfree_skb(skb);
 out:
index 5bbef4fdcb439f7c3445278dc580b3f0aaacf907..648fa1490ea7f96d1f373b4f8e6b167ed70e82e3 100644 (file)
@@ -262,7 +262,8 @@ static int __init ic_open_devs(void)
        /* wait for a carrier on at least one device */
        start = jiffies;
        next_msg = start + msecs_to_jiffies(CONF_CARRIER_TIMEOUT/12);
-       while (jiffies - start < msecs_to_jiffies(CONF_CARRIER_TIMEOUT)) {
+       while (time_before(jiffies, start +
+                          msecs_to_jiffies(CONF_CARRIER_TIMEOUT))) {
                int wait, elapsed;
 
                for_each_netdev(&init_net, dev)
index 8dd3d9f19d82de36f3125ce8910a09ae34772c02..d189c5262bdbd3f44d77ca8cbba149ecdb8c809d 100644 (file)
@@ -82,6 +82,52 @@ config NF_TABLES_ARP
        help
          This option enables the ARP support for nf_tables.
 
+config NF_NAT_IPV4
+       tristate "IPv4 NAT"
+       depends on NF_CONNTRACK_IPV4
+       default m if NETFILTER_ADVANCED=n
+       select NF_NAT
+       help
+         The IPv4 NAT option allows masquerading, port forwarding and other
+         forms of full Network Address Port Translation. This can be
+         controlled by iptables or nft.
+
+if NF_NAT_IPV4
+
+config NF_NAT_SNMP_BASIC
+       tristate "Basic SNMP-ALG support"
+       depends on NF_CONNTRACK_SNMP
+       depends on NETFILTER_ADVANCED
+       default NF_NAT && NF_CONNTRACK_SNMP
+       ---help---
+
+         This module implements an Application Layer Gateway (ALG) for
+         SNMP payloads.  In conjunction with NAT, it allows a network
+         management system to access multiple private networks with
+         conflicting addresses.  It works by modifying IP addresses
+         inside SNMP payloads to match IP-layer NAT mapping.
+
+         This is the "basic" form of SNMP-ALG, as described in RFC 2962
+
+         To compile it as a module, choose M here.  If unsure, say N.
+
+config NF_NAT_PROTO_GRE
+       tristate
+       depends on NF_CT_PROTO_GRE
+
+config NF_NAT_PPTP
+       tristate
+       depends on NF_CONNTRACK
+       default NF_CONNTRACK_PPTP
+       select NF_NAT_PROTO_GRE
+
+config NF_NAT_H323
+       tristate
+       depends on NF_CONNTRACK
+       default NF_CONNTRACK_H323
+
+endif # NF_NAT_IPV4
+
 config IP_NF_IPTABLES
        tristate "IP tables support (required for filtering/masq/NAT)"
        default m if NETFILTER_ADVANCED=n
@@ -170,19 +216,21 @@ config IP_NF_TARGET_SYNPROXY
          To compile it as a module, choose M here. If unsure, say N.
 
 # NAT + specific targets: nf_conntrack
-config NF_NAT_IPV4
-       tristate "IPv4 NAT"
+config IP_NF_NAT
+       tristate "iptables NAT support"
        depends on NF_CONNTRACK_IPV4
        default m if NETFILTER_ADVANCED=n
        select NF_NAT
+       select NF_NAT_IPV4
+       select NETFILTER_XT_NAT
        help
-         The IPv4 NAT option allows masquerading, port forwarding and other
-         forms of full Network Address Port Translation.  It is controlled by
-         the `nat' table in iptables: see the man page for iptables(8).
+         This enables the `nat' table in iptables. This allows masquerading,
+         port forwarding and other forms of full Network Address Port
+         Translation.
 
          To compile it as a module, choose M here.  If unsure, say N.
 
-if NF_NAT_IPV4
+if IP_NF_NAT
 
 config NF_NAT_MASQUERADE_IPV4
        tristate "IPv4 masquerade support"
@@ -227,47 +275,7 @@ config IP_NF_TARGET_REDIRECT
        (e.g. when running oldconfig). It selects
        CONFIG_NETFILTER_XT_TARGET_REDIRECT.
 
-endif
-
-config NF_NAT_SNMP_BASIC
-       tristate "Basic SNMP-ALG support"
-       depends on NF_CONNTRACK_SNMP && NF_NAT_IPV4
-       depends on NETFILTER_ADVANCED
-       default NF_NAT && NF_CONNTRACK_SNMP
-       ---help---
-
-         This module implements an Application Layer Gateway (ALG) for
-         SNMP payloads.  In conjunction with NAT, it allows a network
-         management system to access multiple private networks with
-         conflicting addresses.  It works by modifying IP addresses
-         inside SNMP payloads to match IP-layer NAT mapping.
-
-         This is the "basic" form of SNMP-ALG, as described in RFC 2962
-
-         To compile it as a module, choose M here.  If unsure, say N.
-
-# If they want FTP, set to $CONFIG_IP_NF_NAT (m or y),
-# or $CONFIG_IP_NF_FTP (m or y), whichever is weaker.
-# From kconfig-language.txt:
-#
-#           <expr> '&&' <expr>                   (6)
-#
-# (6) Returns the result of min(/expr/, /expr/).
-
-config NF_NAT_PROTO_GRE
-       tristate
-       depends on NF_NAT_IPV4 && NF_CT_PROTO_GRE
-
-config NF_NAT_PPTP
-       tristate
-       depends on NF_CONNTRACK && NF_NAT_IPV4
-       default NF_NAT_IPV4 && NF_CONNTRACK_PPTP
-       select NF_NAT_PROTO_GRE
-
-config NF_NAT_H323
-       tristate
-       depends on NF_CONNTRACK && NF_NAT_IPV4
-       default NF_NAT_IPV4 && NF_CONNTRACK_H323
+endif # IP_NF_NAT
 
 # mangle + specific targets
 config IP_NF_MANGLE
index 7d019aefb0ed944791122d3a87d73e791ab99d86..14488cc5fd2ca21f3b3ceaa5a9f23c5cd6ed86f7 100644 (file)
@@ -45,7 +45,7 @@ obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o
 # the three instances of ip_tables
 obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o
 obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o
-obj-$(CONFIG_NF_NAT_IPV4) += iptable_nat.o
+obj-$(CONFIG_IP_NF_NAT) += iptable_nat.o
 obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o
 obj-$(CONFIG_IP_NF_SECURITY) += iptable_security.o
 
index 2510c02c2d2168ffcd27f286c7eab3ca75165f26..e90f83a3415b464014cecf0f072b2188f6889b7a 100644 (file)
@@ -285,7 +285,7 @@ clusterip_hashfn(const struct sk_buff *skb,
        }
 
        /* node numbers are 1..n, not 0..n */
-       return (((u64)hashval * config->num_total_nodes) >> 32) + 1;
+       return reciprocal_scale(hashval, config->num_total_nodes) + 1;
 }
 
 static inline int
index a3c59a077a5f0574f02584b0068de0703d5cb3dc..57f7c98041394998fe390735aa5b8cd2602b3f90 100644 (file)
@@ -311,7 +311,7 @@ static int ping_check_bind_addr(struct sock *sk, struct inet_sock *isk,
                if (addr->sin_addr.s_addr == htonl(INADDR_ANY))
                        chk_addr_ret = RTN_LOCAL;
 
-               if ((sysctl_ip_nonlocal_bind == 0 &&
+               if ((net->ipv4.sysctl_ip_nonlocal_bind == 0 &&
                    isk->freebind == 0 && isk->transparent == 0 &&
                     chk_addr_ret != RTN_LOCAL) ||
                    chk_addr_ret == RTN_MULTICAST ||
index eaa4b000c7b443898be7c5ce36f4da4eb20158a6..234a43e233dcf0b64252817deea8d8d969de6ccb 100644 (file)
@@ -596,12 +596,12 @@ static struct fib_nh_exception *fnhe_oldest(struct fnhe_hash_bucket *hash)
 
 static inline u32 fnhe_hashfun(__be32 daddr)
 {
+       static u32 fnhe_hashrnd __read_mostly;
        u32 hval;
 
-       hval = (__force u32) daddr;
-       hval ^= (hval >> 11) ^ (hval >> 22);
-
-       return hval & (FNHE_HASH_SIZE - 1);
+       net_get_random_once(&fnhe_hashrnd, sizeof(fnhe_hashrnd));
+       hval = jhash_1word((__force u32) daddr, fnhe_hashrnd);
+       return hash_32(hval, FNHE_HASH_SHIFT);
 }
 
 static void fill_route_from_fnhe(struct rtable *rt, struct fib_nh_exception *fnhe)
@@ -628,12 +628,12 @@ static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw,
 
        spin_lock_bh(&fnhe_lock);
 
-       hash = nh->nh_exceptions;
+       hash = rcu_dereference(nh->nh_exceptions);
        if (!hash) {
                hash = kzalloc(FNHE_HASH_SIZE * sizeof(*hash), GFP_ATOMIC);
                if (!hash)
                        goto out_unlock;
-               nh->nh_exceptions = hash;
+               rcu_assign_pointer(nh->nh_exceptions, hash);
        }
 
        hash += hval;
@@ -1242,7 +1242,7 @@ static unsigned int ipv4_mtu(const struct dst_entry *dst)
 
 static struct fib_nh_exception *find_exception(struct fib_nh *nh, __be32 daddr)
 {
-       struct fnhe_hash_bucket *hash = nh->nh_exceptions;
+       struct fnhe_hash_bucket *hash = rcu_dereference(nh->nh_exceptions);
        struct fib_nh_exception *fnhe;
        u32 hval;
 
index c0c75688896e06bd1b64384c94e7db758f842d0b..0431a8f3c8f458538e37543a0b37a091da0c04bb 100644 (file)
@@ -25,7 +25,7 @@
 
 extern int sysctl_tcp_syncookies;
 
-static u32 syncookie_secret[2][16-4+SHA_DIGEST_WORDS];
+static u32 syncookie_secret[2][16-4+SHA_DIGEST_WORDS] __read_mostly;
 
 #define COOKIEBITS 24  /* Upper bits store count */
 #define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1)
index 79a007c5255883f9d96011682c67ea8aac15a835..1599966f4639259799fbb8a3cbd7f61d276cd7ef 100644 (file)
@@ -285,13 +285,6 @@ static struct ctl_table ipv4_table[] = {
                .extra1         = &ip_ttl_min,
                .extra2         = &ip_ttl_max,
        },
-       {
-               .procname       = "ip_nonlocal_bind",
-               .data           = &sysctl_ip_nonlocal_bind,
-               .maxlen         = sizeof(int),
-               .mode           = 0644,
-               .proc_handler   = proc_dointvec
-       },
        {
                .procname       = "tcp_syn_retries",
                .data           = &sysctl_tcp_syn_retries,
@@ -450,6 +443,16 @@ static struct ctl_table ipv4_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec
        },
+#ifdef CONFIG_IP_MULTICAST
+       {
+               .procname       = "igmp_qrv",
+               .data           = &sysctl_igmp_qrv,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &one
+       },
+#endif
        {
                .procname       = "inet_peer_threshold",
                .data           = &inet_peer_threshold,
@@ -838,6 +841,13 @@ static struct ctl_table ipv4_net_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
+       {
+               .procname       = "ip_nonlocal_bind",
+               .data           = &init_net.ipv4.sysctl_ip_nonlocal_bind,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec
+       },
        {
                .procname       = "fwmark_reflect",
                .data           = &init_net.ipv4.sysctl_fwmark_reflect,
index d5de69bc04f581ac589ae0f6fe7fcc3646b2cc3e..bb395d46a3898136afe615c73ac311fd2832f6f1 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/module.h>
 #include <net/tcp.h>
 
-
 #define BICTCP_BETA_SCALE    1024      /* Scale factor beta calculation
                                         * max_cwnd = snd_cwnd * beta
                                         */
@@ -46,11 +45,10 @@ MODULE_PARM_DESC(initial_ssthresh, "initial value of slow start threshold");
 module_param(smooth_part, int, 0644);
 MODULE_PARM_DESC(smooth_part, "log(B/(B*Smin))/log(B/(B-1))+B, # of RTT from Wmax-B to Wmax");
 
-
 /* BIC TCP Parameters */
 struct bictcp {
        u32     cnt;            /* increase cwnd by 1 after ACKs */
-       u32     last_max_cwnd;  /* last maximum snd_cwnd */
+       u32     last_max_cwnd;  /* last maximum snd_cwnd */
        u32     loss_cwnd;      /* congestion window at last loss */
        u32     last_cwnd;      /* the last snd_cwnd */
        u32     last_time;      /* time when updated last_cwnd */
@@ -103,7 +101,7 @@ static inline void bictcp_update(struct bictcp *ca, u32 cwnd)
 
        /* binary increase */
        if (cwnd < ca->last_max_cwnd) {
-               __u32   dist = (ca->last_max_cwnd - cwnd)
+               __u32   dist = (ca->last_max_cwnd - cwnd)
                        / BICTCP_B;
 
                if (dist > max_increment)
@@ -154,7 +152,6 @@ static void bictcp_cong_avoid(struct sock *sk, u32 ack, u32 acked)
                bictcp_update(ca, tp->snd_cwnd);
                tcp_cong_avoid_ai(tp, ca->cnt);
        }
-
 }
 
 /*
@@ -177,7 +174,6 @@ static u32 bictcp_recalc_ssthresh(struct sock *sk)
 
        ca->loss_cwnd = tp->snd_cwnd;
 
-
        if (tp->snd_cwnd <= low_window)
                return max(tp->snd_cwnd >> 1U, 2U);
        else
@@ -188,6 +184,7 @@ static u32 bictcp_undo_cwnd(struct sock *sk)
 {
        const struct tcp_sock *tp = tcp_sk(sk);
        const struct bictcp *ca = inet_csk_ca(sk);
+
        return max(tp->snd_cwnd, ca->loss_cwnd);
 }
 
@@ -206,12 +203,12 @@ static void bictcp_acked(struct sock *sk, u32 cnt, s32 rtt)
 
        if (icsk->icsk_ca_state == TCP_CA_Open) {
                struct bictcp *ca = inet_csk_ca(sk);
+
                cnt -= ca->delayed_ack >> ACK_RATIO_SHIFT;
                ca->delayed_ack += cnt;
        }
 }
 
-
 static struct tcp_congestion_ops bictcp __read_mostly = {
        .init           = bictcp_init,
        .ssthresh       = bictcp_recalc_ssthresh,
index 7b09d8b49fa51271cc0fa99a3fcda9f017c0f469..80248f56c89f0b3dc8481aea2212fac819924772 100644 (file)
@@ -142,7 +142,6 @@ static int __init tcp_congestion_default(void)
 }
 late_initcall(tcp_congestion_default);
 
-
 /* Build string with list of available congestion control values */
 void tcp_get_available_congestion_control(char *buf, size_t maxlen)
 {
@@ -154,7 +153,6 @@ void tcp_get_available_congestion_control(char *buf, size_t maxlen)
                offs += snprintf(buf + offs, maxlen - offs,
                                 "%s%s",
                                 offs == 0 ? "" : " ", ca->name);
-
        }
        rcu_read_unlock();
 }
@@ -186,7 +184,6 @@ void tcp_get_allowed_congestion_control(char *buf, size_t maxlen)
                offs += snprintf(buf + offs, maxlen - offs,
                                 "%s%s",
                                 offs == 0 ? "" : " ", ca->name);
-
        }
        rcu_read_unlock();
 }
@@ -230,7 +227,6 @@ out:
        return ret;
 }
 
-
 /* Change congestion control for socket */
 int tcp_set_congestion_control(struct sock *sk, const char *name)
 {
@@ -337,6 +333,7 @@ EXPORT_SYMBOL_GPL(tcp_reno_cong_avoid);
 u32 tcp_reno_ssthresh(struct sock *sk)
 {
        const struct tcp_sock *tp = tcp_sk(sk);
+
        return max(tp->snd_cwnd >> 1U, 2U);
 }
 EXPORT_SYMBOL_GPL(tcp_reno_ssthresh);
index a9bd8a4828a9e5c2da275626c11c6c953a1b3dd6..20de0118c98e455447128513610ba04b13f3cd61 100644 (file)
@@ -82,12 +82,13 @@ MODULE_PARM_DESC(hystart_ack_delta, "spacing between ack's indicating train (mse
 /* BIC TCP Parameters */
 struct bictcp {
        u32     cnt;            /* increase cwnd by 1 after ACKs */
-       u32     last_max_cwnd;  /* last maximum snd_cwnd */
+       u32     last_max_cwnd;  /* last maximum snd_cwnd */
        u32     loss_cwnd;      /* congestion window at last loss */
        u32     last_cwnd;      /* the last snd_cwnd */
        u32     last_time;      /* time when updated last_cwnd */
        u32     bic_origin_point;/* origin point of bic function */
-       u32     bic_K;          /* time to origin point from the beginning of the current epoch */
+       u32     bic_K;          /* time to origin point
+                                  from the beginning of the current epoch */
        u32     delay_min;      /* min delay (msec << 3) */
        u32     epoch_start;    /* beginning of an epoch */
        u32     ack_cnt;        /* number of acks */
@@ -219,7 +220,7 @@ static inline void bictcp_update(struct bictcp *ca, u32 cwnd)
        ca->last_time = tcp_time_stamp;
 
        if (ca->epoch_start == 0) {
-               ca->epoch_start = tcp_time_stamp;       /* record the beginning of an epoch */
+               ca->epoch_start = tcp_time_stamp;       /* record beginning */
                ca->ack_cnt = 1;                        /* start counting */
                ca->tcp_cwnd = cwnd;                    /* syn with cubic */
 
@@ -263,9 +264,9 @@ static inline void bictcp_update(struct bictcp *ca, u32 cwnd)
 
        /* c/rtt * (t-K)^3 */
        delta = (cube_rtt_scale * offs * offs * offs) >> (10+3*BICTCP_HZ);
-       if (t < ca->bic_K)                                      /* below origin*/
+       if (t < ca->bic_K)                            /* below origin*/
                bic_target = ca->bic_origin_point - delta;
-       else                                                    /* above origin*/
+       else                                          /* above origin*/
                bic_target = ca->bic_origin_point + delta;
 
        /* cubic function - calc bictcp_cnt*/
@@ -285,13 +286,14 @@ static inline void bictcp_update(struct bictcp *ca, u32 cwnd)
        /* TCP Friendly */
        if (tcp_friendliness) {
                u32 scale = beta_scale;
+
                delta = (cwnd * scale) >> 3;
                while (ca->ack_cnt > delta) {           /* update tcp cwnd */
                        ca->ack_cnt -= delta;
                        ca->tcp_cwnd++;
                }
 
-               if (ca->tcp_cwnd > cwnd)      /* if bic is slower than tcp */
+               if (ca->tcp_cwnd > cwnd) {      /* if bic is slower than tcp */
                        delta = ca->tcp_cwnd - cwnd;
                        max_cnt = cwnd / delta;
                        if (ca->cnt > max_cnt)
@@ -320,7 +322,6 @@ static void bictcp_cong_avoid(struct sock *sk, u32 ack, u32 acked)
                bictcp_update(ca, tp->snd_cwnd);
                tcp_cong_avoid_ai(tp, ca->cnt);
        }
-
 }
 
 static u32 bictcp_recalc_ssthresh(struct sock *sk)
@@ -452,7 +453,8 @@ static int __init cubictcp_register(void)
         * based on SRTT of 100ms
         */
 
-       beta_scale = 8*(BICTCP_BETA_SCALE+beta)/ 3 / (BICTCP_BETA_SCALE - beta);
+       beta_scale = 8*(BICTCP_BETA_SCALE+beta) / 3
+               / (BICTCP_BETA_SCALE - beta);
 
        cube_rtt_scale = (bic_scale * 10);      /* 1024*c/rtt */
 
index ed3f2ad42e0f0ea881e507d8c91e7962d336d824..0d73f9ddb55b8d55204643541dad651cd9d6eb06 100644 (file)
@@ -9,7 +9,6 @@
  *      2 of the License, or (at your option) any later version.
  */
 
-
 #include <linux/module.h>
 #include <linux/inet_diag.h>
 
@@ -35,13 +34,13 @@ static void tcp_diag_get_info(struct sock *sk, struct inet_diag_msg *r,
 }
 
 static void tcp_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
-               struct inet_diag_req_v2 *r, struct nlattr *bc)
+                         struct inet_diag_req_v2 *r, struct nlattr *bc)
 {
        inet_diag_dump_icsk(&tcp_hashinfo, skb, cb, r, bc);
 }
 
 static int tcp_diag_dump_one(struct sk_buff *in_skb, const struct nlmsghdr *nlh,
-               struct inet_diag_req_v2 *req)
+                            struct inet_diag_req_v2 *req)
 {
        return inet_diag_dump_one_icsk(&tcp_hashinfo, in_skb, nlh, req);
 }
index 1c4908280d921fbe9a9e21e4fd55d1a87f2db706..882c08aae2f58d02bb78212a4eba4d25d7e9c123 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/module.h>
 #include <net/tcp.h>
 
-
 /* From AIMD tables from RFC 3649 appendix B,
  * with fixed-point MD scaled <<8.
  */
@@ -17,78 +16,78 @@ static const struct hstcp_aimd_val {
        unsigned int cwnd;
        unsigned int md;
 } hstcp_aimd_vals[] = {
- {     38,  128, /*  0.50 */ },
- {    118,  112, /*  0.44 */ },
- {    221,  104, /*  0.41 */ },
- {    347,   98, /*  0.38 */ },
- {    495,   93, /*  0.37 */ },
- {    663,   89, /*  0.35 */ },
- {    851,   86, /*  0.34 */ },
- {   1058,   83, /*  0.33 */ },
- {   1284,   81, /*  0.32 */ },
- {   1529,   78, /*  0.31 */ },
- {   1793,   76, /*  0.30 */ },
- {   2076,   74, /*  0.29 */ },
- {   2378,   72, /*  0.28 */ },
- {   2699,   71, /*  0.28 */ },
- {   3039,   69, /*  0.27 */ },
- {   3399,   68, /*  0.27 */ },
- {   3778,   66, /*  0.26 */ },
- {   4177,   65, /*  0.26 */ },
- {   4596,   64, /*  0.25 */ },
- {   5036,   62, /*  0.25 */ },
- {   5497,   61, /*  0.24 */ },
- {   5979,   60, /*  0.24 */ },
- {   6483,   59, /*  0.23 */ },
- {   7009,   58, /*  0.23 */ },
- {   7558,   57, /*  0.22 */ },
- {   8130,   56, /*  0.22 */ },
- {   8726,   55, /*  0.22 */ },
- {   9346,   54, /*  0.21 */ },
- {   9991,   53, /*  0.21 */ },
- {  10661,   52, /*  0.21 */ },
- {  11358,   52, /*  0.20 */ },
- {  12082,   51, /*  0.20 */ },
- {  12834,   50, /*  0.20 */ },
- {  13614,   49, /*  0.19 */ },
- {  14424,   48, /*  0.19 */ },
- {  15265,   48, /*  0.19 */ },
- {  16137,   47, /*  0.19 */ },
- {  17042,   46, /*  0.18 */ },
- {  17981,   45, /*  0.18 */ },
- {  18955,   45, /*  0.18 */ },
- {  19965,   44, /*  0.17 */ },
- {  21013,   43, /*  0.17 */ },
- {  22101,   43, /*  0.17 */ },
- {  23230,   42, /*  0.17 */ },
- {  24402,   41, /*  0.16 */ },
- {  25618,   41, /*  0.16 */ },
- {  26881,   40, /*  0.16 */ },
- {  28193,   39, /*  0.16 */ },
- {  29557,   39, /*  0.15 */ },
- {  30975,   38, /*  0.15 */ },
- {  32450,   38, /*  0.15 */ },
- {  33986,   37, /*  0.15 */ },
- {  35586,   36, /*  0.14 */ },
- {  37253,   36, /*  0.14 */ },
- {  38992,   35, /*  0.14 */ },
- {  40808,   35, /*  0.14 */ },
- {  42707,   34, /*  0.13 */ },
- {  44694,   33, /*  0.13 */ },
- {  46776,   33, /*  0.13 */ },
- {  48961,   32, /*  0.13 */ },
- {  51258,   32, /*  0.13 */ },
- {  53677,   31, /*  0.12 */ },
- {  56230,   30, /*  0.12 */ },
- {  58932,   30, /*  0.12 */ },
- {  61799,   29, /*  0.12 */ },
- {  64851,   28, /*  0.11 */ },
- {  68113,   28, /*  0.11 */ },
- {  71617,   27, /*  0.11 */ },
- {  75401,   26, /*  0.10 */ },
- {  79517,   26, /*  0.10 */ },
- {  84035,   25, /*  0.10 */ },
- {  89053,   24, /*  0.10 */ },
      {     38,  128, /*  0.50 */ },
      {    118,  112, /*  0.44 */ },
      {    221,  104, /*  0.41 */ },
      {    347,   98, /*  0.38 */ },
      {    495,   93, /*  0.37 */ },
      {    663,   89, /*  0.35 */ },
      {    851,   86, /*  0.34 */ },
      {   1058,   83, /*  0.33 */ },
      {   1284,   81, /*  0.32 */ },
      {   1529,   78, /*  0.31 */ },
      {   1793,   76, /*  0.30 */ },
      {   2076,   74, /*  0.29 */ },
      {   2378,   72, /*  0.28 */ },
      {   2699,   71, /*  0.28 */ },
      {   3039,   69, /*  0.27 */ },
      {   3399,   68, /*  0.27 */ },
      {   3778,   66, /*  0.26 */ },
      {   4177,   65, /*  0.26 */ },
      {   4596,   64, /*  0.25 */ },
      {   5036,   62, /*  0.25 */ },
      {   5497,   61, /*  0.24 */ },
      {   5979,   60, /*  0.24 */ },
      {   6483,   59, /*  0.23 */ },
      {   7009,   58, /*  0.23 */ },
      {   7558,   57, /*  0.22 */ },
      {   8130,   56, /*  0.22 */ },
      {   8726,   55, /*  0.22 */ },
      {   9346,   54, /*  0.21 */ },
      {   9991,   53, /*  0.21 */ },
      {  10661,   52, /*  0.21 */ },
      {  11358,   52, /*  0.20 */ },
      {  12082,   51, /*  0.20 */ },
      {  12834,   50, /*  0.20 */ },
      {  13614,   49, /*  0.19 */ },
      {  14424,   48, /*  0.19 */ },
      {  15265,   48, /*  0.19 */ },
      {  16137,   47, /*  0.19 */ },
      {  17042,   46, /*  0.18 */ },
      {  17981,   45, /*  0.18 */ },
      {  18955,   45, /*  0.18 */ },
      {  19965,   44, /*  0.17 */ },
      {  21013,   43, /*  0.17 */ },
      {  22101,   43, /*  0.17 */ },
      {  23230,   42, /*  0.17 */ },
      {  24402,   41, /*  0.16 */ },
      {  25618,   41, /*  0.16 */ },
      {  26881,   40, /*  0.16 */ },
      {  28193,   39, /*  0.16 */ },
      {  29557,   39, /*  0.15 */ },
      {  30975,   38, /*  0.15 */ },
      {  32450,   38, /*  0.15 */ },
      {  33986,   37, /*  0.15 */ },
      {  35586,   36, /*  0.14 */ },
      {  37253,   36, /*  0.14 */ },
      {  38992,   35, /*  0.14 */ },
      {  40808,   35, /*  0.14 */ },
      {  42707,   34, /*  0.13 */ },
      {  44694,   33, /*  0.13 */ },
      {  46776,   33, /*  0.13 */ },
      {  48961,   32, /*  0.13 */ },
      {  51258,   32, /*  0.13 */ },
      {  53677,   31, /*  0.12 */ },
      {  56230,   30, /*  0.12 */ },
      {  58932,   30, /*  0.12 */ },
      {  61799,   29, /*  0.12 */ },
      {  64851,   28, /*  0.11 */ },
      {  68113,   28, /*  0.11 */ },
      {  71617,   27, /*  0.11 */ },
      {  75401,   26, /*  0.10 */ },
      {  79517,   26, /*  0.10 */ },
      {  84035,   25, /*  0.10 */ },
      {  89053,   24, /*  0.10 */ },
 };
 
 #define HSTCP_AIMD_MAX ARRAY_SIZE(hstcp_aimd_vals)
index 031361311a8b92b1f7ab1172fb00e3bbb0503129..58469fff6c18fd444c95366caa04ab60965d654a 100644 (file)
@@ -98,7 +98,8 @@ static inline void measure_rtt(struct sock *sk, u32 srtt)
        }
 }
 
-static void measure_achieved_throughput(struct sock *sk, u32 pkts_acked, s32 rtt)
+static void measure_achieved_throughput(struct sock *sk,
+                                       u32 pkts_acked, s32 rtt)
 {
        const struct inet_connection_sock *icsk = inet_csk(sk);
        const struct tcp_sock *tp = tcp_sk(sk);
@@ -148,8 +149,8 @@ static inline void htcp_beta_update(struct htcp *ca, u32 minRTT, u32 maxRTT)
        if (use_bandwidth_switch) {
                u32 maxB = ca->maxB;
                u32 old_maxB = ca->old_maxB;
-               ca->old_maxB = ca->maxB;
 
+               ca->old_maxB = ca->maxB;
                if (!between(5 * maxB, 4 * old_maxB, 6 * old_maxB)) {
                        ca->beta = BETA_MIN;
                        ca->modeswitch = 0;
@@ -270,6 +271,7 @@ static void htcp_state(struct sock *sk, u8 new_state)
        case TCP_CA_Open:
                {
                        struct htcp *ca = inet_csk_ca(sk);
+
                        if (ca->undo_last_cong) {
                                ca->last_cong = jiffies;
                                ca->undo_last_cong = 0;
index d8f8f05a49516ec2d9213f10af77b82fbf32bff7..f963b274f2b0436755ebe8bb5586b1ec9682c336 100644 (file)
@@ -29,7 +29,6 @@ static int rtt0 = 25;
 module_param(rtt0, int, 0644);
 MODULE_PARM_DESC(rtt0, "reference rout trip time (ms)");
 
-
 /* This is called to refresh values for hybla parameters */
 static inline void hybla_recalc_param (struct sock *sk)
 {
index 5999b3972e6449d616facb628d27116ab8876ac2..1d5a30a90adf6194d3b2d2215276f52c0a3f4632 100644 (file)
@@ -284,7 +284,7 @@ static void tcp_illinois_cong_avoid(struct sock *sk, u32 ack, u32 acked)
                delta = (tp->snd_cwnd_cnt * ca->alpha) >> ALPHA_SHIFT;
                if (delta >= tp->snd_cwnd) {
                        tp->snd_cwnd = min(tp->snd_cwnd + delta / tp->snd_cwnd,
-                                          (u32) tp->snd_cwnd_clamp);
+                                          (u32)tp->snd_cwnd_clamp);
                        tp->snd_cwnd_cnt = 0;
                }
        }
@@ -299,7 +299,6 @@ static u32 tcp_illinois_ssthresh(struct sock *sk)
        return max(tp->snd_cwnd - ((tp->snd_cwnd * ca->beta) >> BETA_SHIFT), 2U);
 }
 
-
 /* Extract info for Tcp socket info provided via netlink. */
 static void tcp_illinois_info(struct sock *sk, u32 ext,
                              struct sk_buff *skb)
index a906e0200ff26144727a1c6c90718cf1fa492dde..f97003ad0af55998df0be629f3c99cd093fd4e43 100644 (file)
@@ -1888,21 +1888,21 @@ static inline void tcp_reset_reno_sack(struct tcp_sock *tp)
        tp->sacked_out = 0;
 }
 
-static void tcp_clear_retrans_partial(struct tcp_sock *tp)
+void tcp_clear_retrans(struct tcp_sock *tp)
 {
        tp->retrans_out = 0;
        tp->lost_out = 0;
-
        tp->undo_marker = 0;
        tp->undo_retrans = -1;
+       tp->fackets_out = 0;
+       tp->sacked_out = 0;
 }
 
-void tcp_clear_retrans(struct tcp_sock *tp)
+static inline void tcp_init_undo(struct tcp_sock *tp)
 {
-       tcp_clear_retrans_partial(tp);
-
-       tp->fackets_out = 0;
-       tp->sacked_out = 0;
+       tp->undo_marker = tp->snd_una;
+       /* Retransmission still in flight may cause DSACKs later. */
+       tp->undo_retrans = tp->retrans_out ? : -1;
 }
 
 /* Enter Loss state. If we detect SACK reneging, forget all SACK information
@@ -1925,18 +1925,18 @@ void tcp_enter_loss(struct sock *sk)
                tp->prior_ssthresh = tcp_current_ssthresh(sk);
                tp->snd_ssthresh = icsk->icsk_ca_ops->ssthresh(sk);
                tcp_ca_event(sk, CA_EVENT_LOSS);
+               tcp_init_undo(tp);
        }
        tp->snd_cwnd       = 1;
        tp->snd_cwnd_cnt   = 0;
        tp->snd_cwnd_stamp = tcp_time_stamp;
 
-       tcp_clear_retrans_partial(tp);
+       tp->retrans_out = 0;
+       tp->lost_out = 0;
 
        if (tcp_is_reno(tp))
                tcp_reset_reno_sack(tp);
 
-       tp->undo_marker = tp->snd_una;
-
        skb = tcp_write_queue_head(sk);
        is_reneg = skb && (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED);
        if (is_reneg) {
@@ -1950,9 +1950,6 @@ void tcp_enter_loss(struct sock *sk)
                if (skb == tcp_send_head(sk))
                        break;
 
-               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) || is_reneg) {
                        TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_ACKED;
@@ -2671,8 +2668,7 @@ static void tcp_enter_recovery(struct sock *sk, bool ece_ack)
        NET_INC_STATS_BH(sock_net(sk), mib_idx);
 
        tp->prior_ssthresh = 0;
-       tp->undo_marker = tp->snd_una;
-       tp->undo_retrans = tp->retrans_out ? : -1;
+       tcp_init_undo(tp);
 
        if (inet_csk(sk)->icsk_ca_state < TCP_CA_CWR) {
                if (!ece_ack)
@@ -2971,7 +2967,8 @@ void tcp_rearm_rto(struct sock *sk)
                if (icsk->icsk_pending == ICSK_TIME_EARLY_RETRANS ||
                    icsk->icsk_pending == ICSK_TIME_LOSS_PROBE) {
                        struct sk_buff *skb = tcp_write_queue_head(sk);
-                       const u32 rto_time_stamp = TCP_SKB_CB(skb)->when + rto;
+                       const u32 rto_time_stamp =
+                               tcp_skb_timestamp(skb) + rto;
                        s32 delta = (s32)(rto_time_stamp - tcp_time_stamp);
                        /* delta may not be positive if the socket is locked
                         * when the retrans timer fires and is rescheduled.
@@ -5910,7 +5907,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
        struct request_sock *req;
        struct tcp_sock *tp = tcp_sk(sk);
        struct dst_entry *dst = NULL;
-       __u32 isn = TCP_SKB_CB(skb)->when;
+       __u32 isn = TCP_SKB_CB(skb)->tcp_tw_isn;
        bool want_cookie = false, fastopen;
        struct flowi fl;
        struct tcp_fastopen_cookie foc = { .len = -1 };
index cd17f009aede03524f741b84a413478b2d38ef7c..7881b96d2b7214a87563c52ab0d06f15efc7e1bb 100644 (file)
@@ -90,7 +90,6 @@ int sysctl_tcp_tw_reuse __read_mostly;
 int sysctl_tcp_low_latency __read_mostly;
 EXPORT_SYMBOL(sysctl_tcp_low_latency);
 
-
 #ifdef CONFIG_TCP_MD5SIG
 static int tcp_v4_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key,
                               __be32 daddr, __be32 saddr, const struct tcphdr *th);
@@ -438,8 +437,9 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
                skb = tcp_write_queue_head(sk);
                BUG_ON(!skb);
 
-               remaining = icsk->icsk_rto - min(icsk->icsk_rto,
-                               tcp_time_stamp - TCP_SKB_CB(skb)->when);
+               remaining = icsk->icsk_rto -
+                           min(icsk->icsk_rto,
+                               tcp_time_stamp - tcp_skb_timestamp(skb));
 
                if (remaining) {
                        inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
@@ -1269,7 +1269,7 @@ struct request_sock_ops tcp_request_sock_ops __read_mostly = {
        .send_ack       =       tcp_v4_reqsk_send_ack,
        .destructor     =       tcp_v4_reqsk_destructor,
        .send_reset     =       tcp_v4_send_reset,
-       .syn_ack_timeout =      tcp_syn_ack_timeout,
+       .syn_ack_timeout =      tcp_syn_ack_timeout,
 };
 
 static const struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = {
@@ -1559,7 +1559,17 @@ bool tcp_prequeue(struct sock *sk, struct sk_buff *skb)
            skb_queue_len(&tp->ucopy.prequeue) == 0)
                return false;
 
-       skb_dst_force(skb);
+       /* Before escaping RCU protected region, we need to take care of skb
+        * dst. Prequeue is only enabled for established sockets.
+        * For such sockets, we might need the skb dst only to set sk->sk_rx_dst
+        * Instead of doing full sk_rx_dst validity here, let's perform
+        * an optimistic check.
+        */
+       if (likely(sk->sk_rx_dst))
+               skb_dst_drop(skb);
+       else
+               skb_dst_force(skb);
+
        __skb_queue_tail(&tp->ucopy.prequeue, skb);
        tp->ucopy.memory += skb->truesize;
        if (tp->ucopy.memory > sk->sk_rcvbuf) {
@@ -1628,7 +1638,7 @@ int tcp_v4_rcv(struct sk_buff *skb)
        TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
                                    skb->len - th->doff * 4);
        TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
-       TCP_SKB_CB(skb)->when    = 0;
+       TCP_SKB_CB(skb)->tcp_tw_isn = 0;
        TCP_SKB_CB(skb)->ip_dsfield = ipv4_get_dsfield(iph);
        TCP_SKB_CB(skb)->sacked  = 0;
 
@@ -1765,9 +1775,11 @@ void inet_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
 {
        struct dst_entry *dst = skb_dst(skb);
 
-       dst_hold(dst);
-       sk->sk_rx_dst = dst;
-       inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
+       if (dst) {
+               dst_hold(dst);
+               sk->sk_rx_dst = dst;
+               inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
+       }
 }
 EXPORT_SYMBOL(inet_sk_rx_dst_set);
 
@@ -2183,7 +2195,7 @@ int tcp_seq_open(struct inode *inode, struct file *file)
 
        s = ((struct seq_file *)file->private_data)->private;
        s->family               = afinfo->family;
-       s->last_pos             = 0;
+       s->last_pos             = 0;
        return 0;
 }
 EXPORT_SYMBOL(tcp_seq_open);
index 1649988bd1b632f09506da9e685dc643c64161fd..a058f411d3a6bd1441282e39da5d34152435513e 100644 (file)
@@ -232,7 +232,7 @@ kill:
                u32 isn = tcptw->tw_snd_nxt + 65535 + 2;
                if (isn == 0)
                        isn++;
-               TCP_SKB_CB(skb)->when = isn;
+               TCP_SKB_CB(skb)->tcp_tw_isn = isn;
                return TCP_TW_SYN;
        }
 
index bc1b83cb8309f5d4737d7751e9542823e044b587..72912533a191ba0335bc8c0d3ec3817d5af45f23 100644 (file)
@@ -288,35 +288,14 @@ static int tcp_v4_gso_send_check(struct sk_buff *skb)
 
 static struct sk_buff **tcp4_gro_receive(struct sk_buff **head, struct sk_buff *skb)
 {
-       /* Use the IP hdr immediately proceeding for this transport */
-       const struct iphdr *iph = skb_gro_network_header(skb);
-       __wsum wsum;
-
        /* Don't bother verifying checksum if we're going to flush anyway. */
-       if (NAPI_GRO_CB(skb)->flush)
-               goto skip_csum;
-
-       wsum = NAPI_GRO_CB(skb)->csum;
-
-       switch (skb->ip_summed) {
-       case CHECKSUM_NONE:
-               wsum = skb_checksum(skb, skb_gro_offset(skb), skb_gro_len(skb),
-                                   0);
-
-               /* fall through */
-
-       case CHECKSUM_COMPLETE:
-               if (!tcp_v4_check(skb_gro_len(skb), iph->saddr, iph->daddr,
-                                 wsum)) {
-                       skb->ip_summed = CHECKSUM_UNNECESSARY;
-                       break;
-               }
-
+       if (!NAPI_GRO_CB(skb)->flush &&
+           skb_gro_checksum_validate(skb, IPPROTO_TCP,
+                                     inet_gro_compute_pseudo)) {
                NAPI_GRO_CB(skb)->flush = 1;
                return NULL;
        }
 
-skip_csum:
        return tcp_gro_receive(head, skb);
 }
 
index 5a7c41fbc6d3399686ff47ab5102ef7cc1a9ea42..7f1280dcad579315b393b0e2c7953fa05d0e3cf0 100644 (file)
@@ -550,7 +550,7 @@ static unsigned int tcp_syn_options(struct sock *sk, struct sk_buff *skb,
 
        if (likely(sysctl_tcp_timestamps && *md5 == NULL)) {
                opts->options |= OPTION_TS;
-               opts->tsval = TCP_SKB_CB(skb)->when + tp->tsoffset;
+               opts->tsval = tcp_skb_timestamp(skb) + tp->tsoffset;
                opts->tsecr = tp->rx_opt.ts_recent;
                remaining -= TCPOLEN_TSTAMP_ALIGNED;
        }
@@ -618,7 +618,7 @@ static unsigned int tcp_synack_options(struct sock *sk,
        }
        if (likely(ireq->tstamp_ok)) {
                opts->options |= OPTION_TS;
-               opts->tsval = TCP_SKB_CB(skb)->when;
+               opts->tsval = tcp_skb_timestamp(skb);
                opts->tsecr = req->ts_recent;
                remaining -= TCPOLEN_TSTAMP_ALIGNED;
        }
@@ -647,7 +647,6 @@ static unsigned int tcp_established_options(struct sock *sk, struct sk_buff *skb
                                        struct tcp_out_options *opts,
                                        struct tcp_md5sig_key **md5)
 {
-       struct tcp_skb_cb *tcb = skb ? TCP_SKB_CB(skb) : NULL;
        struct tcp_sock *tp = tcp_sk(sk);
        unsigned int size = 0;
        unsigned int eff_sacks;
@@ -666,7 +665,7 @@ static unsigned int tcp_established_options(struct sock *sk, struct sk_buff *skb
 
        if (likely(tp->rx_opt.tstamp_ok)) {
                opts->options |= OPTION_TS;
-               opts->tsval = tcb ? tcb->when + tp->tsoffset : 0;
+               opts->tsval = skb ? tcp_skb_timestamp(skb) + tp->tsoffset : 0;
                opts->tsecr = tp->rx_opt.ts_recent;
                size += TCPOLEN_TSTAMP_ALIGNED;
        }
@@ -886,8 +885,6 @@ 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);
@@ -975,7 +972,10 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
                TCP_ADD_STATS(sock_net(sk), TCP_MIB_OUTSEGS,
                              tcp_skb_pcount(skb));
 
+       /* Our usage of tstamp should remain private */
+       skb->tstamp.tv64 = 0;
        err = icsk->icsk_af_ops->queue_xmit(sk, skb, &inet->cork.fl);
+
        if (likely(err <= 0))
                return err;
 
@@ -1146,10 +1146,6 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len,
 
        buff->ip_summed = skb->ip_summed;
 
-       /* Looks stupid, but our code really uses when of
-        * skbs, which it never sent before. --ANK
-        */
-       TCP_SKB_CB(buff)->when = TCP_SKB_CB(skb)->when;
        buff->tstamp = skb->tstamp;
        tcp_fragment_tstamp(skb, buff);
 
@@ -1874,8 +1870,8 @@ static int tcp_mtu_probe(struct sock *sk)
        tcp_init_tso_segs(sk, nskb, nskb->len);
 
        /* We're ready to send.  If this fails, the probe will
-        * be resegmented into mss-sized pieces by tcp_write_xmit(). */
-       TCP_SKB_CB(nskb)->when = tcp_time_stamp;
+        * be resegmented into mss-sized pieces by tcp_write_xmit().
+        */
        if (!tcp_transmit_skb(sk, nskb, 1, GFP_ATOMIC)) {
                /* Decrement cwnd here because we are sending
                 * effectively two packets. */
@@ -1935,8 +1931,8 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
                BUG_ON(!tso_segs);
 
                if (unlikely(tp->repair) && tp->repair_queue == TCP_SEND_QUEUE) {
-                       /* "when" is used as a start point for the retransmit timer */
-                       TCP_SKB_CB(skb)->when = tcp_time_stamp;
+                       /* "skb_mstamp" is used as a start point for the retransmit timer */
+                       skb_mstamp_get(&skb->skb_mstamp);
                        goto repair; /* Skip network transmission */
                }
 
@@ -2000,8 +1996,6 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
                    unlikely(tso_fragment(sk, skb, limit, mss_now, gfp)))
                        break;
 
-               TCP_SKB_CB(skb)->when = tcp_time_stamp;
-
                if (unlikely(tcp_transmit_skb(sk, skb, 1, gfp)))
                        break;
 
@@ -2499,7 +2493,6 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
        /* Make a copy, if the first transmission SKB clone we made
         * is still in somebody's hands, else make a clone.
         */
-       TCP_SKB_CB(skb)->when = tcp_time_stamp;
 
        /* make sure skb->data is aligned on arches that require it
         * and check if ack-trimming & collapsing extended the headroom
@@ -2544,7 +2537,7 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
 
                /* Save stamp of the first retransmit. */
                if (!tp->retrans_stamp)
-                       tp->retrans_stamp = TCP_SKB_CB(skb)->when;
+                       tp->retrans_stamp = tcp_skb_timestamp(skb);
 
                /* snd_nxt is stored to detect loss of retransmitted segment,
                 * see tcp_input.c tcp_sacktag_write_queue().
@@ -2752,7 +2745,6 @@ void tcp_send_active_reset(struct sock *sk, gfp_t priority)
        tcp_init_nondata_skb(skb, tcp_acceptable_seq(sk),
                             TCPHDR_ACK | TCPHDR_RST);
        /* Send it off. */
-       TCP_SKB_CB(skb)->when = tcp_time_stamp;
        if (tcp_transmit_skb(sk, skb, 0, priority))
                NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTFAILED);
 
@@ -2791,7 +2783,6 @@ int tcp_send_synack(struct sock *sk)
                TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_ACK;
                TCP_ECN_send_synack(tcp_sk(sk), skb);
        }
-       TCP_SKB_CB(skb)->when = tcp_time_stamp;
        return tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC);
 }
 
@@ -2835,10 +2826,10 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
        memset(&opts, 0, sizeof(opts));
 #ifdef CONFIG_SYN_COOKIES
        if (unlikely(req->cookie_ts))
-               TCP_SKB_CB(skb)->when = cookie_init_timestamp(req);
+               skb->skb_mstamp.stamp_jiffies = cookie_init_timestamp(req);
        else
 #endif
-       TCP_SKB_CB(skb)->when = tcp_time_stamp;
+       skb_mstamp_get(&skb->skb_mstamp);
        tcp_header_size = tcp_synack_options(sk, req, mss, skb, &opts, &md5,
                                             foc) + sizeof(*th);
 
@@ -3086,7 +3077,7 @@ int tcp_connect(struct sock *sk)
        skb_reserve(buff, MAX_TCP_HEADER);
 
        tcp_init_nondata_skb(buff, tp->write_seq++, TCPHDR_SYN);
-       tp->retrans_stamp = TCP_SKB_CB(buff)->when = tcp_time_stamp;
+       tp->retrans_stamp = tcp_time_stamp;
        tcp_connect_queue_skb(sk, buff);
        TCP_ECN_send_syn(sk, buff);
 
@@ -3194,7 +3185,7 @@ void tcp_send_ack(struct sock *sk)
        tcp_init_nondata_skb(buff, tcp_acceptable_seq(sk), TCPHDR_ACK);
 
        /* Send it off, this clears delayed acks for us. */
-       TCP_SKB_CB(buff)->when = tcp_time_stamp;
+       skb_mstamp_get(&buff->skb_mstamp);
        tcp_transmit_skb(sk, buff, 0, sk_gfp_atomic(sk, GFP_ATOMIC));
 }
 
@@ -3226,7 +3217,7 @@ static int tcp_xmit_probe_skb(struct sock *sk, int urgent)
         * send it.
         */
        tcp_init_nondata_skb(skb, tp->snd_una - !urgent, TCPHDR_ACK);
-       TCP_SKB_CB(skb)->when = tcp_time_stamp;
+       skb_mstamp_get(&skb->skb_mstamp);
        return tcp_transmit_skb(sk, skb, 0, GFP_ATOMIC);
 }
 
@@ -3270,7 +3261,6 @@ int tcp_write_wakeup(struct sock *sk)
                        tcp_set_skb_tso_segs(sk, skb, mss);
 
                TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_PSH;
-               TCP_SKB_CB(skb)->when = tcp_time_stamp;
                err = tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC);
                if (!err)
                        tcp_event_new_data_sent(sk, skb);
index 3b66610d41562035c541304924fc27a4eb416a6e..ebf5ff57526eab65018005c47a907545e61cacf6 100644 (file)
@@ -83,7 +83,6 @@ static struct {
        struct tcp_log  *log;
 } tcp_probe;
 
-
 static inline int tcp_probe_used(void)
 {
        return (tcp_probe.head - tcp_probe.tail) & (bufsize - 1);
@@ -101,7 +100,6 @@ static inline int tcp_probe_avail(void)
                si4.sin_addr.s_addr = inet->inet_##mem##addr;   \
        } while (0)                                             \
 
-
 /*
  * Hook inserted to be called before each receive packet.
  * Note: arguments must match tcp_rcv_established()!
@@ -194,8 +192,8 @@ static int tcpprobe_sprint(char *tbuf, int n)
 
        return scnprintf(tbuf, n,
                        "%lu.%09lu %pISpc %pISpc %d %#x %#x %u %u %u %u %u\n",
-                       (unsigned long) tv.tv_sec,
-                       (unsigned long) tv.tv_nsec,
+                       (unsigned long)tv.tv_sec,
+                       (unsigned long)tv.tv_nsec,
                        &p->src, &p->dst, p->length, p->snd_nxt, p->snd_una,
                        p->snd_cwnd, p->ssthresh, p->snd_wnd, p->srtt, p->rcv_wnd);
 }
index 8250949b88538db4e0f2d318050518855e74cf3d..6824afb65d9335532fe2bf61edce82cab8c3fd9c 100644 (file)
@@ -31,10 +31,10 @@ static void tcp_scalable_cong_avoid(struct sock *sk, u32 ack, u32 acked)
 static u32 tcp_scalable_ssthresh(struct sock *sk)
 {
        const struct tcp_sock *tp = tcp_sk(sk);
+
        return max(tp->snd_cwnd - (tp->snd_cwnd>>TCP_SCALABLE_MD_SCALE), 2U);
 }
 
-
 static struct tcp_congestion_ops tcp_scalable __read_mostly = {
        .ssthresh       = tcp_scalable_ssthresh,
        .cong_avoid     = tcp_scalable_cong_avoid,
index df90cd1ce37f71b145d3f5cde4bf1d9b4a4cfd22..a339e7ba05a434954744b6716a7d57be0400066c 100644 (file)
@@ -135,10 +135,9 @@ static bool retransmits_timed_out(struct sock *sk,
        if (!inet_csk(sk)->icsk_retransmits)
                return false;
 
-       if (unlikely(!tcp_sk(sk)->retrans_stamp))
-               start_ts = TCP_SKB_CB(tcp_write_queue_head(sk))->when;
-       else
-               start_ts = tcp_sk(sk)->retrans_stamp;
+       start_ts = tcp_sk(sk)->retrans_stamp;
+       if (unlikely(!start_ts))
+               start_ts = tcp_skb_timestamp(tcp_write_queue_head(sk));
 
        if (likely(timeout == 0)) {
                linear_backoff_thresh = ilog2(TCP_RTO_MAX/rto_base);
index b40ad897f94509201988b6b9cc589e599d036851..a6afde666ab1284ea53c24ce80b2c287ff42073b 100644 (file)
@@ -51,7 +51,6 @@ MODULE_PARM_DESC(beta, "upper bound of packets in network");
 module_param(gamma, int, 0644);
 MODULE_PARM_DESC(gamma, "limit on increase (scale by 2)");
 
-
 /* There are several situations when we must "re-start" Vegas:
  *
  *  o when a connection is established
@@ -133,7 +132,6 @@ EXPORT_SYMBOL_GPL(tcp_vegas_pkts_acked);
 
 void tcp_vegas_state(struct sock *sk, u8 ca_state)
 {
-
        if (ca_state == TCP_CA_Open)
                vegas_enable(sk);
        else
@@ -285,7 +283,6 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 acked)
        /* Use normal slow start */
        else if (tp->snd_cwnd <= tp->snd_ssthresh)
                tcp_slow_start(tp, acked);
-
 }
 
 /* Extract info for Tcp socket info provided via netlink. */
index 8276977d2c854729d9c7a0e3e501b2dee9db4c3d..a4d2d2d88dcae7c00cf4db83d8b13ce6b143b3b4 100644 (file)
@@ -175,7 +175,6 @@ static void tcp_veno_cong_avoid(struct sock *sk, u32 ack, u32 acked)
                                } else
                                        tp->snd_cwnd_cnt++;
                        }
-
                }
                if (tp->snd_cwnd < 2)
                        tp->snd_cwnd = 2;
index b94a04ae2ed5672eca79a172c5c3467a677186a1..81911a92356c6a7a50b63800dc070d6943c280f3 100644 (file)
@@ -42,7 +42,6 @@ struct westwood {
        u8     reset_rtt_min;    /* Reset RTT min to next RTT sample*/
 };
 
-
 /* TCP Westwood functions and constants */
 #define TCP_WESTWOOD_RTT_MIN   (HZ/20) /* 50ms */
 #define TCP_WESTWOOD_INIT_RTT  (20*HZ) /* maybe too conservative?! */
@@ -153,7 +152,6 @@ static inline void update_rtt_min(struct westwood *w)
                w->rtt_min = min(w->rtt, w->rtt_min);
 }
 
-
 /*
  * @westwood_fast_bw
  * It is called when we are in fast path. In particular it is called when
@@ -208,7 +206,6 @@ static inline u32 westwood_acked_count(struct sock *sk)
        return w->cumul_ack;
 }
 
-
 /*
  * TCP Westwood
  * Here limit is evaluated as Bw estimation*RTTmin (for obtaining it
@@ -219,6 +216,7 @@ static u32 tcp_westwood_bw_rttmin(const struct sock *sk)
 {
        const struct tcp_sock *tp = tcp_sk(sk);
        const struct westwood *w = inet_csk_ca(sk);
+
        return max_t(u32, (w->bw_est * w->rtt_min) / tp->mss_cache, 2);
 }
 
@@ -254,12 +252,12 @@ static void tcp_westwood_event(struct sock *sk, enum tcp_ca_event event)
        }
 }
 
-
 /* Extract info for Tcp socket info provided via netlink. */
 static void tcp_westwood_info(struct sock *sk, u32 ext,
                              struct sk_buff *skb)
 {
        const struct westwood *ca = inet_csk_ca(sk);
+
        if (ext & (1 << (INET_DIAG_VEGASINFO - 1))) {
                struct tcpvegas_info info = {
                        .tcpv_enabled = 1,
@@ -271,7 +269,6 @@ static void tcp_westwood_info(struct sock *sk, u32 ext,
        }
 }
 
-
 static struct tcp_congestion_ops tcp_westwood __read_mostly = {
        .init           = tcp_westwood_init,
        .ssthresh       = tcp_reno_ssthresh,
index 599b79b8eac07298a34cff43ae87e546bdb36847..cd72732185989b41d1a3f9167eacbf44c235cc01 100644 (file)
@@ -54,10 +54,8 @@ static void tcp_yeah_init(struct sock *sk)
        /* Ensure the MD arithmetic works.  This is somewhat pedantic,
         * since I don't think we will see a cwnd this large. :) */
        tp->snd_cwnd_clamp = min_t(u32, tp->snd_cwnd_clamp, 0xffffffff/128);
-
 }
 
-
 static void tcp_yeah_pkts_acked(struct sock *sk, u32 pkts_acked, s32 rtt_us)
 {
        const struct inet_connection_sock *icsk = inet_csk(sk);
@@ -84,7 +82,7 @@ static void tcp_yeah_cong_avoid(struct sock *sk, u32 ack, u32 acked)
                /* Scalable */
 
                tp->snd_cwnd_cnt += yeah->pkts_acked;
-               if (tp->snd_cwnd_cnt > min(tp->snd_cwnd, TCP_SCALABLE_AI_CNT)){
+               if (tp->snd_cwnd_cnt > min(tp->snd_cwnd, TCP_SCALABLE_AI_CNT)) {
                        if (tp->snd_cwnd < tp->snd_cwnd_clamp)
                                tp->snd_cwnd++;
                        tp->snd_cwnd_cnt = 0;
@@ -120,7 +118,6 @@ static void tcp_yeah_cong_avoid(struct sock *sk, u32 ack, u32 acked)
         */
 
        if (after(ack, yeah->vegas.beg_snd_nxt)) {
-
                /* We do the Vegas calculations only if we got enough RTT
                 * samples that we can be reasonably sure that we got
                 * at least one RTT sample that wasn't from a delayed ACK.
@@ -189,7 +186,6 @@ static void tcp_yeah_cong_avoid(struct sock *sk, u32 ack, u32 acked)
                        }
 
                        yeah->lastQ = queue;
-
                }
 
                /* Save the extent of the current window so we can use this
@@ -205,7 +201,8 @@ static void tcp_yeah_cong_avoid(struct sock *sk, u32 ack, u32 acked)
        }
 }
 
-static u32 tcp_yeah_ssthresh(struct sock *sk) {
+static u32 tcp_yeah_ssthresh(struct sock *sk)
+{
        const struct tcp_sock *tp = tcp_sk(sk);
        struct yeah *yeah = inet_csk_ca(sk);
        u32 reduction;
index f57c0e4c2326fd1a7d4b85cbdb4304657e5660f8..cd0db5471bb5eb6048208404aab71253867e1eec 100644 (file)
@@ -99,6 +99,7 @@
 #include <linux/slab.h>
 #include <net/tcp_states.h>
 #include <linux/skbuff.h>
+#include <linux/netdevice.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <net/net_namespace.h>
@@ -224,7 +225,7 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum,
                remaining = (high - low) + 1;
 
                rand = prandom_u32();
-               first = (((u64)rand * remaining) >> 32) + low;
+               first = reciprocal_scale(rand, remaining) + low;
                /*
                 * force rand to be an odd multiple of UDP_HTABLE_SIZE
                 */
@@ -448,7 +449,7 @@ begin:
                        }
                } else if (score == badness && reuseport) {
                        matches++;
-                       if (((u64)hash * matches) >> 32 == 0)
+                       if (reciprocal_scale(hash, matches) == 0)
                                result = sk;
                        hash = next_pseudo_random32(hash);
                }
@@ -529,7 +530,7 @@ begin:
                        }
                } else if (score == badness && reuseport) {
                        matches++;
-                       if (((u64)hash * matches) >> 32 == 0)
+                       if (reciprocal_scale(hash, matches) == 0)
                                result = sk;
                        hash = next_pseudo_random32(hash);
                }
@@ -1787,6 +1788,10 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
        if (sk != NULL) {
                int ret;
 
+               if (udp_sk(sk)->convert_csum && uh->check && !IS_UDPLITE(sk))
+                       skb_checksum_try_convert(skb, IPPROTO_UDP, uh->check,
+                                                inet_compute_pseudo);
+
                ret = udp_queue_rcv_skb(sk, skb);
                sock_put(sk);
 
@@ -1967,7 +1972,7 @@ void udp_v4_early_demux(struct sk_buff *skb)
                return;
 
        skb->sk = sk;
-       skb->destructor = sock_edemux;
+       skb->destructor = sock_efree;
        dst = sk->sk_rx_dst;
 
        if (dst)
index 59035bc3008d2bc45ec87e9eea4145120bf664be..52d5f46abf863f77eafb78ac059b75580dfd2e50 100644 (file)
@@ -228,30 +228,24 @@ unlock:
 }
 EXPORT_SYMBOL(udp_del_offload);
 
-static struct sk_buff **udp_gro_receive(struct sk_buff **head, struct sk_buff *skb)
+struct sk_buff **udp_gro_receive(struct sk_buff **head, struct sk_buff *skb,
+                                struct udphdr *uh)
 {
        struct udp_offload_priv *uo_priv;
        struct sk_buff *p, **pp = NULL;
-       struct udphdr *uh, *uh2;
-       unsigned int hlen, off;
+       struct udphdr *uh2;
+       unsigned int off = skb_gro_offset(skb);
        int flush = 1;
 
        if (NAPI_GRO_CB(skb)->udp_mark ||
-           (!skb->encapsulation && skb->ip_summed != CHECKSUM_COMPLETE))
+           (skb->ip_summed != CHECKSUM_PARTIAL &&
+            NAPI_GRO_CB(skb)->csum_cnt == 0 &&
+            !NAPI_GRO_CB(skb)->csum_valid))
                goto out;
 
        /* mark that this skb passed once through the udp gro layer */
        NAPI_GRO_CB(skb)->udp_mark = 1;
 
-       off  = skb_gro_offset(skb);
-       hlen = off + sizeof(*uh);
-       uh   = skb_gro_header_fast(skb, off);
-       if (skb_gro_header_hard(skb, hlen)) {
-               uh = skb_gro_header_slow(skb, hlen, off);
-               if (unlikely(!uh))
-                       goto out;
-       }
-
        rcu_read_lock();
        uo_priv = rcu_dereference(udp_offload_base);
        for (; uo_priv != NULL; uo_priv = rcu_dereference(uo_priv->next)) {
@@ -269,7 +263,12 @@ unflush:
                        continue;
 
                uh2 = (struct udphdr   *)(p->data + off);
-               if ((*(u32 *)&uh->source != *(u32 *)&uh2->source)) {
+
+               /* Match ports and either checksums are either both zero
+                * or nonzero.
+                */
+               if ((*(u32 *)&uh->source != *(u32 *)&uh2->source) ||
+                   (!uh->check ^ !uh2->check)) {
                        NAPI_GRO_CB(p)->same_flow = 0;
                        continue;
                }
@@ -286,7 +285,33 @@ out:
        return pp;
 }
 
-static int udp_gro_complete(struct sk_buff *skb, int nhoff)
+static struct sk_buff **udp4_gro_receive(struct sk_buff **head,
+                                        struct sk_buff *skb)
+{
+       struct udphdr *uh = udp_gro_udphdr(skb);
+
+       if (unlikely(!uh))
+               goto flush;
+
+       /* Don't bother verifying checksum if we're going to flush anyway. */
+       if (!NAPI_GRO_CB(skb)->flush)
+               goto skip;
+
+       if (skb_gro_checksum_validate_zero_check(skb, IPPROTO_UDP, uh->check,
+                                                inet_gro_compute_pseudo))
+               goto flush;
+       else if (uh->check)
+               skb_gro_checksum_try_convert(skb, IPPROTO_UDP, uh->check,
+                                            inet_gro_compute_pseudo);
+skip:
+       return udp_gro_receive(head, skb, uh);
+
+flush:
+       NAPI_GRO_CB(skb)->flush = 1;
+       return NULL;
+}
+
+int udp_gro_complete(struct sk_buff *skb, int nhoff)
 {
        struct udp_offload_priv *uo_priv;
        __be16 newlen = htons(skb->len - nhoff);
@@ -311,12 +336,24 @@ static int udp_gro_complete(struct sk_buff *skb, int nhoff)
        return err;
 }
 
+static int udp4_gro_complete(struct sk_buff *skb, int nhoff)
+{
+       const struct iphdr *iph = ip_hdr(skb);
+       struct udphdr *uh = (struct udphdr *)(skb->data + nhoff);
+
+       if (uh->check)
+               uh->check = ~udp_v4_check(skb->len - nhoff, iph->saddr,
+                                         iph->daddr, 0);
+
+       return udp_gro_complete(skb, nhoff);
+}
+
 static const struct net_offload udpv4_offload = {
        .callbacks = {
                .gso_send_check = udp4_ufo_send_check,
                .gso_segment = udp4_ufo_fragment,
-               .gro_receive  = udp_gro_receive,
-               .gro_complete = udp_gro_complete,
+               .gro_receive  = udp4_gro_receive,
+               .gro_complete = udp4_gro_complete,
        },
 };
 
index 0b239fc1816ed828862f19cdde0f08720a0b43ca..ad4598fcc416cde41211fd466b2b259d6cb98dc9 100644 (file)
@@ -180,7 +180,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
        .rtr_solicits           = MAX_RTR_SOLICITATIONS,
        .rtr_solicit_interval   = RTR_SOLICITATION_INTERVAL,
        .rtr_solicit_delay      = MAX_RTR_SOLICITATION_DELAY,
-       .use_tempaddr           = 0,
+       .use_tempaddr           = 0,
        .temp_valid_lft         = TEMP_VALID_LIFETIME,
        .temp_prefered_lft      = TEMP_PREFERRED_LIFETIME,
        .regen_max_retry        = REGEN_MAX_RETRY,
@@ -1105,8 +1105,8 @@ retry:
        spin_unlock_bh(&ifp->lock);
 
        regen_advance = idev->cnf.regen_max_retry *
-                       idev->cnf.dad_transmits *
-                       NEIGH_VAR(idev->nd_parms, RETRANS_TIME) / HZ;
+                       idev->cnf.dad_transmits *
+                       NEIGH_VAR(idev->nd_parms, RETRANS_TIME) / HZ;
        write_unlock_bh(&idev->lock);
 
        /* A temporary address is created only if this calculated Preferred
@@ -1690,14 +1690,12 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp)
        addrconf_mod_dad_work(ifp, 0);
 }
 
-/* Join to solicited addr multicast group. */
-
+/* Join to solicited addr multicast group.
+ * caller must hold RTNL */
 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;
 
@@ -1705,12 +1703,11 @@ void addrconf_join_solict(struct net_device *dev, const struct in6_addr *addr)
        ipv6_dev_mc_inc(dev, &maddr);
 }
 
+/* caller must hold RTNL */
 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;
 
@@ -1718,12 +1715,11 @@ void addrconf_leave_solict(struct inet6_dev *idev, const struct in6_addr *addr)
        __ipv6_dev_mc_dec(idev, &maddr);
 }
 
+/* caller must hold RTNL */
 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);
@@ -1732,12 +1728,11 @@ static void addrconf_join_anycast(struct inet6_ifaddr *ifp)
        ipv6_dev_ac_inc(ifp->idev->dev, &addr);
 }
 
+/* caller must hold RTNL */
 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);
@@ -3035,7 +3030,7 @@ static int addrconf_ifdown(struct net_device *dev, int how)
                struct hlist_head *h = &inet6_addr_lst[i];
 
                spin_lock_bh(&addrconf_hash_lock);
-       restart:
+restart:
                hlist_for_each_entry_rcu(ifa, h, addr_lst) {
                        if (ifa->idev == idev) {
                                hlist_del_init_rcu(&ifa->addr_lst);
@@ -3547,8 +3542,8 @@ static void __net_exit if6_proc_net_exit(struct net *net)
 }
 
 static struct pernet_operations if6_proc_net_ops = {
-       .init = if6_proc_net_init,
-       .exit = if6_proc_net_exit,
+       .init = if6_proc_net_init,
+       .exit = if6_proc_net_exit,
 };
 
 int __init if6_proc_init(void)
@@ -4773,15 +4768,11 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
                addrconf_leave_solict(ifp->idev, &ifp->addr);
                if (!ipv6_addr_any(&ifp->peer_addr)) {
                        struct rt6_info *rt;
-                       struct net_device *dev = ifp->idev->dev;
-
-                       rt = rt6_lookup(dev_net(dev), &ifp->peer_addr, NULL,
-                                       dev->ifindex, 1);
-                       if (rt) {
-                               dst_hold(&rt->dst);
-                               if (ip6_del_rt(rt))
-                                       dst_free(&rt->dst);
-                       }
+
+                       rt = addrconf_get_prefix_route(&ifp->peer_addr, 128,
+                                                      ifp->idev->dev, 0, 0);
+                       if (rt && ip6_del_rt(rt))
+                               dst_free(&rt->dst);
                }
                dst_hold(&ifp->rt->dst);
 
index 2daa3a133e498cdccfe5695ee62db7c72da8ce25..e4865a3ebe1d776c7463cfa8a75b7332e9b1d445 100644 (file)
@@ -7,15 +7,15 @@
  *
  *     Adapted from linux/net/ipv4/af_inet.c
  *
- *     Fixes:
+ *     Fixes:
  *     piggy, Karl Knutson     :       Socket protocol table
- *     Hideaki YOSHIFUJI       :       sin6_scope_id support
- *     Arnaldo Melo            :       check proc_net_create return, cleanups
+ *     Hideaki YOSHIFUJI       :       sin6_scope_id support
+ *     Arnaldo Melo            :       check proc_net_create return, cleanups
  *
  *     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.
+ *     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) "IPv6: " fmt
@@ -302,7 +302,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
                /* Reproduce AF_INET checks to make the bindings consistent */
                v4addr = addr->sin6_addr.s6_addr32[3];
                chk_addr_ret = inet_addr_type(net, v4addr);
-               if (!sysctl_ip_nonlocal_bind &&
+               if (!net->ipv4.sysctl_ip_nonlocal_bind &&
                    !(inet->freebind || inet->transparent) &&
                    v4addr != htonl(INADDR_ANY) &&
                    chk_addr_ret != RTN_LOCAL &&
index 72a4930bdc0a0e0d43e1a6ad8670e6a1df1608f4..fcffd4e522c88276620cd52c56bbc574b159146f 100644 (file)
  * Authors
  *
  *     Mitsuru KANDA @USAGI       : IPv6 Support
- *     Kazunori MIYAZAWA @USAGI   :
- *     Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+ *     Kazunori MIYAZAWA @USAGI   :
+ *     Kunihiro Ishiguro <kunihiro@ipinfusion.com>
  *
- *     This file is derived from net/ipv4/ah.c.
+ *     This file is derived from net/ipv4/ah.c.
  */
 
 #define pr_fmt(fmt) "IPv6: " fmt
@@ -284,7 +284,7 @@ static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len, int dir)
                        ipv6_rearrange_rthdr(iph, exthdr.rth);
                        break;
 
-               default :
+               default:
                        return 0;
                }
 
@@ -478,7 +478,7 @@ static void ah6_input_done(struct crypto_async_request *base, int err)
        auth_data = ah_tmp_auth(work_iph, hdr_len);
        icv = ah_tmp_icv(ahp->ahash, auth_data, ahp->icv_trunc_len);
 
-       err = memcmp(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG: 0;
+       err = memcmp(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0;
        if (err)
                goto out;
 
@@ -622,7 +622,7 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
                goto out_free;
        }
 
-       err = memcmp(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG: 0;
+       err = memcmp(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0;
        if (err)
                goto out_free;
 
@@ -647,8 +647,8 @@ 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;
-       struct ip_auth_hdr *ah = (struct ip_auth_hdr*)(skb->data+offset);
+       struct ipv6hdr *iph = (struct ipv6hdr *)skb->data;
+       struct ip_auth_hdr *ah = (struct ip_auth_hdr *)(skb->data+offset);
        struct xfrm_state *x;
 
        if (type != ICMPV6_PKT_TOOBIG &&
@@ -755,11 +755,10 @@ static int ah6_rcv_cb(struct sk_buff *skb, int err)
        return 0;
 }
 
-static const struct xfrm_type ah6_type =
-{
+static const struct xfrm_type ah6_type = {
        .description    = "AH6",
        .owner          = THIS_MODULE,
-       .proto          = IPPROTO_AH,
+       .proto          = IPPROTO_AH,
        .flags          = XFRM_TYPE_REPLAY_PROT,
        .init_state     = ah6_init_state,
        .destructor     = ah6_destroy,
index 2101832446896245e54b608bb24f27d83e42a005..ff2de7d9d8e6553de407b7aa5a490fc5c9a40461 100644 (file)
@@ -77,6 +77,7 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
        pac->acl_next = NULL;
        pac->acl_addr = *addr;
 
+       rtnl_lock();
        rcu_read_lock();
        if (ifindex == 0) {
                struct rt6_info *rt;
@@ -137,6 +138,7 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
 
 error:
        rcu_read_unlock();
+       rtnl_unlock();
        if (pac)
                sock_kfree_s(sk, pac, sizeof(*pac));
        return err;
@@ -171,11 +173,13 @@ int ipv6_sock_ac_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
 
        spin_unlock_bh(&ipv6_sk_ac_lock);
 
+       rtnl_lock();
        rcu_read_lock();
        dev = dev_get_by_index_rcu(net, pac->acl_ifindex);
        if (dev)
                ipv6_dev_ac_dec(dev, &pac->acl_addr);
        rcu_read_unlock();
+       rtnl_unlock();
 
        sock_kfree_s(sk, pac, sizeof(*pac));
        return 0;
@@ -198,6 +202,7 @@ void ipv6_sock_ac_close(struct sock *sk)
        spin_unlock_bh(&ipv6_sk_ac_lock);
 
        prev_index = 0;
+       rtnl_lock();
        rcu_read_lock();
        while (pac) {
                struct ipv6_ac_socklist *next = pac->acl_next;
@@ -212,6 +217,7 @@ void ipv6_sock_ac_close(struct sock *sk)
                pac = next;
        }
        rcu_read_unlock();
+       rtnl_unlock();
 }
 
 static void aca_put(struct ifacaddr6 *ac)
@@ -233,6 +239,8 @@ int ipv6_dev_ac_inc(struct net_device *dev, const struct in6_addr *addr)
        struct rt6_info *rt;
        int err;
 
+       ASSERT_RTNL();
+
        idev = in6_dev_get(dev);
 
        if (idev == NULL)
@@ -302,6 +310,8 @@ int __ipv6_dev_ac_dec(struct inet6_dev *idev, const struct in6_addr *addr)
 {
        struct ifacaddr6 *aca, *prev_aca;
 
+       ASSERT_RTNL();
+
        write_lock_bh(&idev->lock);
        prev_aca = NULL;
        for (aca = idev->ac_list; aca; aca = aca->aca_next) {
index 2753319524f1acabb34a0520ea29ee361c1dfe9e..2cdc38338be3fda267d7137cb20fc8bbe72c4466 100644 (file)
@@ -43,13 +43,13 @@ static bool ipv6_mapped_addr_any(const struct in6_addr *a)
 int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
 {
        struct sockaddr_in6     *usin = (struct sockaddr_in6 *) uaddr;
-       struct inet_sock        *inet = inet_sk(sk);
-       struct ipv6_pinfo       *np = inet6_sk(sk);
-       struct in6_addr         *daddr, *final_p, final;
+       struct inet_sock        *inet = inet_sk(sk);
+       struct ipv6_pinfo       *np = inet6_sk(sk);
+       struct in6_addr *daddr, *final_p, final;
        struct dst_entry        *dst;
        struct flowi6           fl6;
        struct ip6_flowlabel    *flowlabel = NULL;
-       struct ipv6_txoptions   *opt;
+       struct ipv6_txoptions   *opt;
        int                     addr_type;
        int                     err;
 
@@ -332,7 +332,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
 {
        struct ipv6_pinfo *np = inet6_sk(sk);
        struct sock_exterr_skb *serr;
-       struct sk_buff *skb, *skb2;
+       struct sk_buff *skb;
        DECLARE_SOCKADDR(struct sockaddr_in6 *, sin, msg->msg_name);
        struct {
                struct sock_extended_err ee;
@@ -342,7 +342,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
        int copied;
 
        err = -EAGAIN;
-       skb = skb_dequeue(&sk->sk_error_queue);
+       skb = sock_dequeue_err_skb(sk);
        if (skb == NULL)
                goto out;
 
@@ -415,17 +415,6 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
        msg->msg_flags |= MSG_ERRQUEUE;
        err = copied;
 
-       /* Reset and regenerate socket error */
-       spin_lock_bh(&sk->sk_error_queue.lock);
-       sk->sk_err = 0;
-       if ((skb2 = skb_peek(&sk->sk_error_queue)) != NULL) {
-               sk->sk_err = SKB_EXT_ERR(skb2)->ee.ee_errno;
-               spin_unlock_bh(&sk->sk_error_queue.lock);
-               sk->sk_error_report(sk);
-       } else {
-               spin_unlock_bh(&sk->sk_error_queue.lock);
-       }
-
 out_free_skb:
        kfree_skb(skb);
 out:
index d15da1377149d3a0fdf846a7a07364e6d1251845..83fc3a385a26782c316914c4f8aafab78fe1a5e2 100644 (file)
  * Authors
  *
  *     Mitsuru KANDA @USAGI       : IPv6 Support
- *     Kazunori MIYAZAWA @USAGI   :
- *     Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+ *     Kazunori MIYAZAWA @USAGI   :
+ *     Kunihiro Ishiguro <kunihiro@ipinfusion.com>
  *
- *     This file is derived from net/ipv4/esp.c
+ *     This file is derived from net/ipv4/esp.c
  */
 
 #define pr_fmt(fmt) "IPv6: " fmt
@@ -598,7 +598,7 @@ static int esp6_init_state(struct xfrm_state *x)
        case XFRM_MODE_BEET:
                if (x->sel.family != AF_INET6)
                        x->props.header_len += IPV4_BEET_PHMAXLEN +
-                                              (sizeof(struct ipv6hdr) - sizeof(struct iphdr));
+                                              (sizeof(struct ipv6hdr) - sizeof(struct iphdr));
                break;
        case XFRM_MODE_TRANSPORT:
                break;
@@ -621,11 +621,10 @@ static int esp6_rcv_cb(struct sk_buff *skb, int err)
        return 0;
 }
 
-static const struct xfrm_type esp6_type =
-{
+static const struct xfrm_type esp6_type = {
        .description    = "ESP6",
-       .owner          = THIS_MODULE,
-       .proto          = IPPROTO_ESP,
+       .owner          = THIS_MODULE,
+       .proto          = IPPROTO_ESP,
        .flags          = XFRM_TYPE_REPLAY_PROT,
        .init_state     = esp6_init_state,
        .destructor     = esp6_destroy,
index 8d67900aa0036139e934354f98aefab13ba51c7a..bfde361b613400df742c21225a1b4b44744ece65 100644 (file)
@@ -142,7 +142,7 @@ static bool ip6_parse_tlv(const struct tlvtype_proc *procs, struct sk_buff *skb)
                default: /* Other TLV code so scan list */
                        if (optlen > len)
                                goto bad;
-                       for (curr=procs; curr->type >= 0; curr++) {
+                       for (curr = procs; curr->type >= 0; curr++) {
                                if (curr->type == nh[off]) {
                                        /* type specific length/alignment
                                           checks will be performed in the
index 06ba3e58320ba45fc3856659e43afd952495db35..394bb824fe4bc9a31119b3e12f170800e5f375e5 100644 (file)
@@ -503,7 +503,7 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)
        msg.type = type;
 
        len = skb->len - msg.offset;
-       len = min_t(unsigned int, len, IPV6_MIN_MTU - sizeof(struct ipv6hdr) -sizeof(struct icmp6hdr));
+       len = min_t(unsigned int, len, IPV6_MIN_MTU - sizeof(struct ipv6hdr) - sizeof(struct icmp6hdr));
        if (len < 0) {
                LIMIT_NETDEBUG(KERN_DEBUG "icmp: len problem\n");
                goto out_dst_release;
@@ -636,7 +636,7 @@ void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info)
                /* now skip over extension headers */
                inner_offset = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr),
                                                &nexthdr, &frag_off);
-               if (inner_offset<0)
+               if (inner_offset < 0)
                        goto out;
        } else {
                inner_offset = sizeof(struct ipv6hdr);
@@ -808,7 +808,7 @@ void icmpv6_flow_init(struct sock *sk, struct flowi6 *fl6,
        memset(fl6, 0, sizeof(*fl6));
        fl6->saddr = *saddr;
        fl6->daddr = *daddr;
-       fl6->flowi6_proto       = IPPROTO_ICMPV6;
+       fl6->flowi6_proto       = IPPROTO_ICMPV6;
        fl6->fl6_icmp_type      = type;
        fl6->fl6_icmp_code      = 0;
        fl6->flowi6_oif         = oif;
@@ -875,8 +875,8 @@ static void __net_exit icmpv6_sk_exit(struct net *net)
 }
 
 static struct pernet_operations icmpv6_sk_ops = {
-       .init = icmpv6_sk_init,
-       .exit = icmpv6_sk_exit,
+       .init = icmpv6_sk_init,
+       .exit = icmpv6_sk_exit,
 };
 
 int __init icmpv6_init(void)
index a245e5ddffbd0450968c44de7d3fcd8a1dd055cf..29b32206e49488e1155900adfcd1707ea909855e 100644 (file)
@@ -63,7 +63,6 @@ int inet6_csk_bind_conflict(const struct sock *sk,
 
        return sk2 != NULL;
 }
-
 EXPORT_SYMBOL_GPL(inet6_csk_bind_conflict);
 
 struct dst_entry *inet6_csk_route_req(struct sock *sk,
@@ -144,7 +143,6 @@ struct request_sock *inet6_csk_search_req(const struct sock *sk,
 
        return NULL;
 }
-
 EXPORT_SYMBOL_GPL(inet6_csk_search_req);
 
 void inet6_csk_reqsk_queue_hash_add(struct sock *sk,
@@ -160,10 +158,9 @@ void inet6_csk_reqsk_queue_hash_add(struct sock *sk,
        reqsk_queue_hash_req(&icsk->icsk_accept_queue, h, req, timeout);
        inet_csk_reqsk_queue_added(sk, timeout);
 }
-
 EXPORT_SYMBOL_GPL(inet6_csk_reqsk_queue_hash_add);
 
-void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr)
+void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr *uaddr)
 {
        struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) uaddr;
 
@@ -175,7 +172,6 @@ void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr)
        sin6->sin6_scope_id = ipv6_iface_scope_id(&sin6->sin6_addr,
                                                  sk->sk_bound_dev_if);
 }
-
 EXPORT_SYMBOL_GPL(inet6_csk_addr2sockaddr);
 
 static inline
index 262e13c02ec27dea15154d9b4af5fd413dd1c504..051dffb49c90e979ca6cc58dd1c2cd2fe9b1cc4c 100644 (file)
@@ -6,7 +6,7 @@
  *             Generic INET6 transport hashtables
  *
  * Authors:    Lotsa people, from code originally in tcp, generalised here
- *             by Arnaldo Carvalho de Melo <acme@mandriva.com>
+ *             by Arnaldo Carvalho de Melo <acme@mandriva.com>
  *
  *     This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -198,7 +198,7 @@ begin:
                        }
                } else if (score == hiscore && reuseport) {
                        matches++;
-                       if (((u64)phash * matches) >> 32 == 0)
+                       if (reciprocal_scale(phash, matches) == 0)
                                result = sk;
                        phash = next_pseudo_random32(phash);
                }
@@ -222,7 +222,6 @@ begin:
        rcu_read_unlock();
        return result;
 }
-
 EXPORT_SYMBOL_GPL(inet6_lookup_listener);
 
 struct sock *inet6_lookup(struct net *net, struct inet_hashinfo *hashinfo,
@@ -238,7 +237,6 @@ struct sock *inet6_lookup(struct net *net, struct inet_hashinfo *hashinfo,
 
        return sk;
 }
-
 EXPORT_SYMBOL_GPL(inet6_lookup);
 
 static int __inet6_check_established(struct inet_timewait_death_row *death_row,
@@ -324,5 +322,4 @@ int inet6_hash_connect(struct inet_timewait_death_row *death_row,
        return __inet_hash_connect(death_row, sk, inet6_sk_port_offset(sk),
                        __inet6_check_established, __inet6_hash);
 }
-
 EXPORT_SYMBOL_GPL(inet6_hash_connect);
index cb4459bd1d294d1901cc03b9c203fbcbf761f53f..76b7f5ee8f4c8a9d8e2b0369135e83d067a31afa 100644 (file)
@@ -643,7 +643,7 @@ static int fib6_commit_metrics(struct dst_entry *dst,
        if (dst->flags & DST_HOST) {
                mp = dst_metrics_write_ptr(dst);
        } else {
-               mp = kzalloc(sizeof(u32) * RTAX_MAX, GFP_KERNEL);
+               mp = kzalloc(sizeof(u32) * RTAX_MAX, GFP_ATOMIC);
                if (!mp)
                        return -ENOMEM;
                dst_init_metrics(dst, mp, 0);
index 4052694c6f2cb196b54ef7d5235d61d74e4ea69c..3dd7d4ebd7cd9dff75c7a89a3a872cf8a073543b 100644 (file)
@@ -136,7 +136,7 @@ static void ip6_fl_gc(unsigned long dummy)
 
        spin_lock(&ip6_fl_lock);
 
-       for (i=0; i<=FL_HASH_MASK; i++) {
+       for (i = 0; i <= FL_HASH_MASK; i++) {
                struct ip6_flowlabel *fl;
                struct ip6_flowlabel __rcu **flp;
 
@@ -239,7 +239,7 @@ static struct ip6_flowlabel *fl_intern(struct net *net,
 
 /* Socket flowlabel lists */
 
-struct ip6_flowlabel * fl6_sock_lookup(struct sock *sk, __be32 label)
+struct ip6_flowlabel *fl6_sock_lookup(struct sock *sk, __be32 label)
 {
        struct ipv6_fl_socklist *sfl;
        struct ipv6_pinfo *np = inet6_sk(sk);
@@ -259,7 +259,6 @@ struct ip6_flowlabel * fl6_sock_lookup(struct sock *sk, __be32 label)
        rcu_read_unlock_bh();
        return NULL;
 }
-
 EXPORT_SYMBOL_GPL(fl6_sock_lookup);
 
 void fl6_free_socklist(struct sock *sk)
@@ -293,11 +292,11 @@ void fl6_free_socklist(struct sock *sk)
    following rthdr.
  */
 
-struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions * opt_space,
-                                        struct ip6_flowlabel * fl,
-                                        struct ipv6_txoptions * fopt)
+struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions *opt_space,
+                                        struct ip6_flowlabel *fl,
+                                        struct ipv6_txoptions *fopt)
 {
-       struct ipv6_txoptions * fl_opt = fl->opt;
+       struct ipv6_txoptions *fl_opt = fl->opt;
 
        if (fopt == NULL || fopt->opt_flen == 0)
                return fl_opt;
@@ -388,7 +387,7 @@ fl_create(struct net *net, struct sock *sk, struct in6_flowlabel_req *freq,
                        goto done;
 
                msg.msg_controllen = olen;
-               msg.msg_control = (void*)(fl->opt+1);
+               msg.msg_control = (void *)(fl->opt+1);
                memset(&flowi6, 0, sizeof(flowi6));
 
                err = ip6_datagram_send_ctl(net, sk, &msg, &flowi6, fl->opt,
@@ -517,7 +516,7 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen)
        struct net *net = sock_net(sk);
        struct ipv6_pinfo *np = inet6_sk(sk);
        struct in6_flowlabel_req freq;
-       struct ipv6_fl_socklist *sfl1=NULL;
+       struct ipv6_fl_socklist *sfl1 = NULL;
        struct ipv6_fl_socklist *sfl;
        struct ipv6_fl_socklist __rcu **sflp;
        struct ip6_flowlabel *fl, *fl1 = NULL;
@@ -542,7 +541,7 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen)
                }
                spin_lock_bh(&ip6_sk_fl_lock);
                for (sflp = &np->ipv6_fl_list;
-                    (sfl = rcu_dereference(*sflp))!=NULL;
+                    (sfl = rcu_dereference(*sflp)) != NULL;
                     sflp = &sfl->next) {
                        if (sfl->fl->label == freq.flr_label) {
                                if (freq.flr_label == (np->flow_label&IPV6_FLOWLABEL_MASK))
index 4578e23834f726ca254d577029c7ccf54ccbed7b..14dacc544c3efc06de8ac80f6bbf6a5ee6cf6b35 100644 (file)
@@ -13,7 +13,7 @@ static ip6_icmp_send_t __rcu *ip6_icmp_send;
 int inet6_register_icmp_sender(ip6_icmp_send_t *fn)
 {
        return (cmpxchg((ip6_icmp_send_t **)&ip6_icmp_send, NULL, fn) == NULL) ?
-               0 : -EBUSY;
+               0 : -EBUSY;
 }
 EXPORT_SYMBOL(inet6_register_icmp_sender);
 
index 51d54dc376f3b1862040f38e6f58e2c75001049c..a3084ab5df6cd1b343af6d725975082f5c4b6eb6 100644 (file)
@@ -15,8 +15,8 @@
  */
 /* Changes
  *
- *     Mitsuru KANDA @USAGI and
- *     YOSHIFUJI Hideaki @USAGI: Remove ipv6_parse_exthdrs().
+ *     Mitsuru KANDA @USAGI and
+ *     YOSHIFUJI Hideaki @USAGI: Remove ipv6_parse_exthdrs().
  */
 
 #include <linux/errno.h>
@@ -65,7 +65,7 @@ int ip6_rcv_finish(struct sk_buff *skb)
 int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
 {
        const struct ipv6hdr *hdr;
-       u32             pkt_len;
+       u32 pkt_len;
        struct inet6_dev *idev;
        struct net *net = dev_net(skb->dev);
 
index 65eda2a8af48280e0c068f24d8ef7adc8c7d8c9e..9952f3fce30a3257f9ea706d76d1ab83febe8c26 100644 (file)
@@ -244,7 +244,7 @@ static struct sk_buff **ipv6_gro_receive(struct sk_buff **head,
                        continue;
 
                iph2 = (struct ipv6hdr *)(p->data + off);
-               first_word = *(__be32 *)iph ^ *(__be32 *)iph2 ;
+               first_word = *(__be32 *)iph ^ *(__be32 *)iph2;
 
                /* All fields must match except length and Traffic Class.
                 * XXX skbs on the gro_list have all been parsed and pulled
@@ -261,6 +261,9 @@ static struct sk_buff **ipv6_gro_receive(struct sk_buff **head,
                /* flush if Traffic Class fields are different */
                NAPI_GRO_CB(p)->flush |= !!(first_word & htonl(0x0FF00000));
                NAPI_GRO_CB(p)->flush |= flush;
+
+               /* Clear flush_id, there's really no concept of ID in IPv6. */
+               NAPI_GRO_CB(p)->flush_id = 0;
        }
 
        NAPI_GRO_CB(skb)->flush |= flush;
@@ -314,6 +317,8 @@ static const struct net_offload sit_offload = {
        .callbacks = {
                .gso_send_check = ipv6_gso_send_check,
                .gso_segment    = ipv6_gso_segment,
+               .gro_receive    = ipv6_gro_receive,
+               .gro_complete   = ipv6_gro_complete,
        },
 };
 
index 315a55d66079cb7129dbfe183e31bcceffd63f99..2e6a0dbf7fb3bf95586dcf690f65e0180f721bdd 100644 (file)
@@ -20,7 +20,7 @@
  *                             etc.
  *
  *      H. von Brand    :       Added missing #include <linux/string.h>
- *     Imran Patel     :       frag id should be in NBO
+ *     Imran Patel     :       frag id should be in NBO
  *      Kazunori MIYAZAWA @USAGI
  *                     :       add ip6_append_data and related functions
  *                             for datagram xmit
@@ -233,7 +233,6 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
        kfree_skb(skb);
        return -EMSGSIZE;
 }
-
 EXPORT_SYMBOL(ip6_xmit);
 
 static int ip6_call_ra_chain(struct sk_buff *skb, int sel)
@@ -555,14 +554,14 @@ static void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt)
 int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
 {
        struct sk_buff *frag;
-       struct rt6_info *rt = (struct rt6_info*)skb_dst(skb);
+       struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
        struct ipv6_pinfo *np = skb->sk ? inet6_sk(skb->sk) : NULL;
        struct ipv6hdr *tmp_hdr;
        struct frag_hdr *fh;
        unsigned int mtu, hlen, left, len;
        int hroom, troom;
        __be32 frag_id = 0;
-       int ptr, offset = 0, err=0;
+       int ptr, offset = 0, err = 0;
        u8 *prevhdr, nexthdr = 0;
        struct net *net = dev_net(skb_dst(skb)->dev);
 
@@ -637,7 +636,7 @@ int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
                }
 
                __skb_pull(skb, hlen);
-               fh = (struct frag_hdr*)__skb_push(skb, sizeof(struct frag_hdr));
+               fh = (struct frag_hdr *)__skb_push(skb, sizeof(struct frag_hdr));
                __skb_push(skb, hlen);
                skb_reset_network_header(skb);
                memcpy(skb_network_header(skb), tmp_hdr, hlen);
@@ -662,7 +661,7 @@ int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
                        if (frag) {
                                frag->ip_summed = CHECKSUM_NONE;
                                skb_reset_transport_header(frag);
-                               fh = (struct frag_hdr*)__skb_push(frag, sizeof(struct frag_hdr));
+                               fh = (struct frag_hdr *)__skb_push(frag, sizeof(struct frag_hdr));
                                __skb_push(frag, hlen);
                                skb_reset_network_header(frag);
                                memcpy(skb_network_header(frag), tmp_hdr,
@@ -681,7 +680,7 @@ int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
                        }
 
                        err = output(skb);
-                       if(!err)
+                       if (!err)
                                IP6_INC_STATS(net, ip6_dst_idev(&rt->dst),
                                              IPSTATS_MIB_FRAGCREATES);
 
@@ -702,11 +701,7 @@ int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
                        return 0;
                }
 
-               while (frag) {
-                       skb = frag->next;
-                       kfree_skb(frag);
-                       frag = skb;
-               }
+               kfree_skb_list(frag);
 
                IP6_INC_STATS(net, ip6_dst_idev(&rt->dst),
                              IPSTATS_MIB_FRAGFAILS);
@@ -742,7 +737,7 @@ slow_path:
        /*
         *      Keep copying data until we run out.
         */
-       while(left > 0) {
+       while (left > 0)        {
                len = left;
                /* IF: it doesn't fit, use 'mtu' - the data space left */
                if (len > mtu)
@@ -865,7 +860,7 @@ static struct dst_entry *ip6_sk_dst_check(struct sock *sk,
        /* Yes, checking route validity in not connected
         * case is not very simple. Take into account,
         * that we do not support routing by source, TOS,
-        * and MSG_DONTROUTE            --ANK (980726)
+        * and MSG_DONTROUTE            --ANK (980726)
         *
         * 1. ip6_rt_check(): If route was host route,
         *    check that cached destination is current.
@@ -1049,7 +1044,7 @@ static inline int ip6_ufo_append_data(struct sock *sk,
                        int getfrag(void *from, char *to, int offset, int len,
                        int odd, struct sk_buff *skb),
                        void *from, int length, int hh_len, int fragheaderlen,
-                       int transhdrlen, int mtu,unsigned int flags,
+                       int transhdrlen, int mtu, unsigned int flags,
                        struct rt6_info *rt)
 
 {
@@ -1072,7 +1067,7 @@ static inline int ip6_ufo_append_data(struct sock *sk,
                skb_reserve(skb, hh_len);
 
                /* create space for UDP/IP header */
-               skb_put(skb,fragheaderlen + transhdrlen);
+               skb_put(skb, fragheaderlen + transhdrlen);
 
                /* initialize network header pointer */
                skb_reset_network_header(skb);
index f9de5a69507252a12cbf1efffbf416721d9c871a..e01bd0399297a7d38917e55709a543b375077db9 100644 (file)
@@ -408,12 +408,12 @@ __u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw)
 {
        const struct ipv6hdr *ipv6h = (const struct ipv6hdr *) raw;
        __u8 nexthdr = ipv6h->nexthdr;
-       __u16 off = sizeof (*ipv6h);
+       __u16 off = sizeof(*ipv6h);
 
        while (ipv6_ext_hdr(nexthdr) && nexthdr != NEXTHDR_NONE) {
                __u16 optlen = 0;
                struct ipv6_opt_hdr *hdr;
-               if (raw + off + sizeof (*hdr) > skb->data &&
+               if (raw + off + sizeof(*hdr) > skb->data &&
                    !pskb_may_pull(skb, raw - skb->data + off + sizeof (*hdr)))
                        break;
 
@@ -530,7 +530,7 @@ ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt,
                        mtu = IPV6_MIN_MTU;
                t->dev->mtu = mtu;
 
-               if ((len = sizeof (*ipv6h) + ntohs(ipv6h->payload_len)) > mtu) {
+               if ((len = sizeof(*ipv6h) + ntohs(ipv6h->payload_len)) > mtu) {
                        rel_type = ICMPV6_PKT_TOOBIG;
                        rel_code = 0;
                        rel_info = mtu;
@@ -991,7 +991,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
                                     t->parms.name);
                goto tx_err_dst_release;
        }
-       mtu = dst_mtu(dst) - sizeof (*ipv6h);
+       mtu = dst_mtu(dst) - sizeof(*ipv6h);
        if (encap_limit >= 0) {
                max_headroom += 8;
                mtu -= 8;
@@ -1083,7 +1083,7 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
        if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
                encap_limit = t->parms.encap_limit;
 
-       memcpy(&fl6, &t->fl.u.ip6, sizeof (fl6));
+       memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6));
        fl6.flowi6_proto = IPPROTO_IPIP;
 
        dsfield = ipv4_get_dsfield(iph);
@@ -1135,7 +1135,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
        } else if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
                encap_limit = t->parms.encap_limit;
 
-       memcpy(&fl6, &t->fl.u.ip6, sizeof (fl6));
+       memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6));
        fl6.flowi6_proto = IPPROTO_IPV6;
 
        dsfield = ipv6_get_dsfield(ipv6h);
@@ -1229,11 +1229,11 @@ static void ip6_tnl_link_config(struct ip6_tnl *t)
 
                if (rt->dst.dev) {
                        dev->hard_header_len = rt->dst.dev->hard_header_len +
-                               sizeof (struct ipv6hdr);
+                               sizeof(struct ipv6hdr);
 
-                       dev->mtu = rt->dst.dev->mtu - sizeof (struct ipv6hdr);
+                       dev->mtu = rt->dst.dev->mtu - sizeof(struct ipv6hdr);
                        if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
-                               dev->mtu-=8;
+                               dev->mtu -= 8;
 
                        if (dev->mtu < IPV6_MIN_MTU)
                                dev->mtu = IPV6_MIN_MTU;
@@ -1350,7 +1350,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        switch (cmd) {
        case SIOCGETTUNNEL:
                if (dev == ip6n->fb_tnl_dev) {
-                       if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p))) {
+                       if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) {
                                err = -EFAULT;
                                break;
                        }
@@ -1362,7 +1362,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                        memset(&p, 0, sizeof(p));
                }
                ip6_tnl_parm_to_user(&p, &t->parms);
-               if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof (p))) {
+               if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p))) {
                        err = -EFAULT;
                }
                break;
@@ -1372,7 +1372,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
                        break;
                err = -EFAULT;
-               if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p)))
+               if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
                        break;
                err = -EINVAL;
                if (p.proto != IPPROTO_IPV6 && p.proto != IPPROTO_IPIP &&
@@ -1407,7 +1407,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 
                if (dev == ip6n->fb_tnl_dev) {
                        err = -EFAULT;
-                       if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p)))
+                       if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
                                break;
                        err = -ENOENT;
                        ip6_tnl_parm_from_user(&p1, &p);
@@ -1482,11 +1482,11 @@ static void ip6_tnl_dev_setup(struct net_device *dev)
        dev->destructor = ip6_dev_free;
 
        dev->type = ARPHRD_TUNNEL6;
-       dev->hard_header_len = LL_MAX_HEADER + sizeof (struct ipv6hdr);
-       dev->mtu = ETH_DATA_LEN - sizeof (struct ipv6hdr);
+       dev->hard_header_len = LL_MAX_HEADER + sizeof(struct ipv6hdr);
+       dev->mtu = ETH_DATA_LEN - sizeof(struct ipv6hdr);
        t = netdev_priv(dev);
        if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
-               dev->mtu-=8;
+               dev->mtu -= 8;
        dev->flags |= IFF_NOARP;
        dev->addr_len = sizeof(struct in6_addr);
        dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
index f9a3fd320d1df23ca1140e3d39e46b4d14a234be..0171f08325c3ff3991485297de4c532fe6992bf8 100644 (file)
@@ -845,7 +845,7 @@ static void ip6mr_destroy_unres(struct mr6_table *mrt, struct mfc6_cache *c)
 
        atomic_dec(&mrt->cache_resolve_queue_len);
 
-       while((skb = skb_dequeue(&c->mfc_un.unres.unresolved)) != NULL) {
+       while ((skb = skb_dequeue(&c->mfc_un.unres.unresolved)) != NULL) {
                if (ipv6_hdr(skb)->version == 0) {
                        struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct ipv6hdr));
                        nlh->nlmsg_type = NLMSG_ERROR;
@@ -1103,7 +1103,7 @@ static void ip6mr_cache_resolve(struct net *net, struct mr6_table *mrt,
         *      Play the pending entries through our router
         */
 
-       while((skb = __skb_dequeue(&uc->mfc_un.unres.unresolved))) {
+       while ((skb = __skb_dequeue(&uc->mfc_un.unres.unresolved))) {
                if (ipv6_hdr(skb)->version == 0) {
                        struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct ipv6hdr));
 
index d1c793cffcb5f44aba0f922f2ebdd3105d51b49f..1b9316e1386a96c899c67888fba4618d3004e69a 100644 (file)
@@ -181,8 +181,7 @@ static int ipcomp6_rcv_cb(struct sk_buff *skb, int err)
        return 0;
 }
 
-static const struct xfrm_type ipcomp6_type =
-{
+static const struct xfrm_type ipcomp6_type = {
        .description    = "IPCOMP6",
        .owner          = THIS_MODULE,
        .proto          = IPPROTO_COMP,
@@ -193,8 +192,7 @@ static const struct xfrm_type ipcomp6_type =
        .hdr_offset     = xfrm6_find_1stfragopt,
 };
 
-static struct xfrm6_protocol ipcomp6_protocol =
-{
+static struct xfrm6_protocol ipcomp6_protocol = {
        .handler        = xfrm6_rcv,
        .cb_handler     = ipcomp6_rcv_cb,
        .err_handler    = ipcomp6_err,
index 0c289982796dfb6e01a761ff4d49616700da3ba8..e1a9583bb4191f44b021e3d39483ed29d1f22fc4 100644 (file)
@@ -66,12 +66,12 @@ int ip6_ra_control(struct sock *sk, int sel)
        if (sk->sk_type != SOCK_RAW || inet_sk(sk)->inet_num != IPPROTO_RAW)
                return -ENOPROTOOPT;
 
-       new_ra = (sel>=0) ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL;
+       new_ra = (sel >= 0) ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL;
 
        write_lock_bh(&ip6_ra_lock);
-       for (rap = &ip6_ra_chain; (ra=*rap) != NULL; rap = &ra->next) {
+       for (rap = &ip6_ra_chain; (ra = *rap) != NULL; rap = &ra->next) {
                if (ra->sk == sk) {
-                       if (sel>=0) {
+                       if (sel >= 0) {
                                write_unlock_bh(&ip6_ra_lock);
                                kfree(new_ra);
                                return -EADDRINUSE;
@@ -130,7 +130,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
        int retv = -ENOPROTOOPT;
 
        if (optval == NULL)
-               val=0;
+               val = 0;
        else {
                if (optlen >= sizeof(int)) {
                        if (get_user(val, (int __user *) optval))
@@ -139,7 +139,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
                        val = 0;
        }
 
-       valbool = (val!=0);
+       valbool = (val != 0);
 
        if (ip6_mroute_opt(optname))
                return ip6_mroute_setsockopt(sk, optname, optval, optlen);
@@ -474,7 +474,7 @@ sticky_done:
                        goto done;
 
                msg.msg_controllen = optlen;
-               msg.msg_control = (void*)(opt+1);
+               msg.msg_control = (void *)(opt+1);
 
                retv = ip6_datagram_send_ctl(net, sk, &msg, &fl6, opt, &junk,
                                             &junk, &junk);
@@ -687,7 +687,7 @@ done:
                        retv = -ENOBUFS;
                        break;
                }
-               gsf = kmalloc(optlen,GFP_KERNEL);
+               gsf = kmalloc(optlen, GFP_KERNEL);
                if (!gsf) {
                        retv = -ENOBUFS;
                        break;
@@ -873,7 +873,6 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname,
 #endif
        return err;
 }
-
 EXPORT_SYMBOL(ipv6_setsockopt);
 
 #ifdef CONFIG_COMPAT
@@ -909,7 +908,6 @@ int compat_ipv6_setsockopt(struct sock *sk, int level, int optname,
 #endif
        return err;
 }
-
 EXPORT_SYMBOL(compat_ipv6_setsockopt);
 #endif
 
@@ -921,7 +919,7 @@ static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_txoptions *opt,
        if (!opt)
                return 0;
 
-       switch(optname) {
+       switch (optname) {
        case IPV6_HOPOPTS:
                hdr = opt->hopopt;
                break;
@@ -1284,9 +1282,9 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
                return -ENOPROTOOPT;
        }
        len = min_t(unsigned int, sizeof(int), len);
-       if(put_user(len, optlen))
+       if (put_user(len, optlen))
                return -EFAULT;
-       if(copy_to_user(optval,&val,len))
+       if (copy_to_user(optval, &val, len))
                return -EFAULT;
        return 0;
 }
@@ -1299,7 +1297,7 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname,
        if (level == SOL_IP && sk->sk_type != SOCK_RAW)
                return udp_prot.getsockopt(sk, level, optname, optval, optlen);
 
-       if(level != SOL_IPV6)
+       if (level != SOL_IPV6)
                return -ENOPROTOOPT;
 
        err = do_ipv6_getsockopt(sk, level, optname, optval, optlen, 0);
@@ -1321,7 +1319,6 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname,
 #endif
        return err;
 }
-
 EXPORT_SYMBOL(ipv6_getsockopt);
 
 #ifdef CONFIG_COMPAT
@@ -1364,7 +1361,6 @@ int compat_ipv6_getsockopt(struct sock *sk, int level, int optname,
 #endif
        return err;
 }
-
 EXPORT_SYMBOL(compat_ipv6_getsockopt);
 #endif
 
index 617f0958e164e7893ca70e80e09d1ed933c95b69..484a94215d8897f80551b760e6045b606dd73076 100644 (file)
 
 #include <net/ip6_checksum.h>
 
-/* Set to 3 to get tracing... */
-#define MCAST_DEBUG 2
-
-#if MCAST_DEBUG >= 3
-#define MDBG(x) printk x
-#else
-#define MDBG(x)
-#endif
-
 /* Ensure that we have struct in6_addr aligned on 32bit word. */
 static void *__mld2_query_bugs[] __attribute__((__unused__)) = {
        BUILD_BUG_ON_NULL(offsetof(struct mld2_query, mld2q_srcs) % 4),
@@ -121,6 +112,7 @@ static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml,
 #define IPV6_MLD_MAX_MSF       64
 
 int sysctl_mld_max_msf __read_mostly = IPV6_MLD_MAX_MSF;
+int sysctl_mld_qrv __read_mostly = MLD_QRV_DEFAULT;
 
 /*
  *     socket join on multicast group
@@ -172,6 +164,7 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
        mc_lst->next = NULL;
        mc_lst->addr = *addr;
 
+       rtnl_lock();
        rcu_read_lock();
        if (ifindex == 0) {
                struct rt6_info *rt;
@@ -185,6 +178,7 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
 
        if (dev == NULL) {
                rcu_read_unlock();
+               rtnl_unlock();
                sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
                return -ENODEV;
        }
@@ -202,6 +196,7 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
 
        if (err) {
                rcu_read_unlock();
+               rtnl_unlock();
                sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
                return err;
        }
@@ -212,6 +207,7 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
        spin_unlock(&ipv6_sk_mc_lock);
 
        rcu_read_unlock();
+       rtnl_unlock();
 
        return 0;
 }
@@ -229,10 +225,11 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
        if (!ipv6_addr_is_multicast(addr))
                return -EINVAL;
 
+       rtnl_lock();
        spin_lock(&ipv6_sk_mc_lock);
        for (lnk = &np->ipv6_mc_list;
             (mc_lst = rcu_dereference_protected(*lnk,
-                       lockdep_is_held(&ipv6_sk_mc_lock))) !=NULL ;
+                       lockdep_is_held(&ipv6_sk_mc_lock))) != NULL;
              lnk = &mc_lst->next) {
                if ((ifindex == 0 || mc_lst->ifindex == ifindex) &&
                    ipv6_addr_equal(&mc_lst->addr, addr)) {
@@ -252,12 +249,15 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
                        } else
                                (void) ip6_mc_leave_src(sk, mc_lst, NULL);
                        rcu_read_unlock();
+                       rtnl_unlock();
+
                        atomic_sub(sizeof(*mc_lst), &sk->sk_omem_alloc);
                        kfree_rcu(mc_lst, rcu);
                        return 0;
                }
        }
        spin_unlock(&ipv6_sk_mc_lock);
+       rtnl_unlock();
 
        return -EADDRNOTAVAIL;
 }
@@ -302,6 +302,7 @@ void ipv6_sock_mc_close(struct sock *sk)
        if (!rcu_access_pointer(np->ipv6_mc_list))
                return;
 
+       rtnl_lock();
        spin_lock(&ipv6_sk_mc_lock);
        while ((mc_lst = rcu_dereference_protected(np->ipv6_mc_list,
                                lockdep_is_held(&ipv6_sk_mc_lock))) != NULL) {
@@ -328,6 +329,7 @@ void ipv6_sock_mc_close(struct sock *sk)
                spin_lock(&ipv6_sk_mc_lock);
        }
        spin_unlock(&ipv6_sk_mc_lock);
+       rtnl_unlock();
 }
 
 int ip6_mc_source(int add, int omode, struct sock *sk,
@@ -390,7 +392,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
                if (!psl)
                        goto done;      /* err = -EADDRNOTAVAIL */
                rv = !0;
-               for (i=0; i<psl->sl_count; i++) {
+               for (i = 0; i < psl->sl_count; i++) {
                        rv = !ipv6_addr_equal(&psl->sl_addr[i], source);
                        if (rv == 0)
                                break;
@@ -407,7 +409,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
                /* update the interface filter */
                ip6_mc_del_src(idev, group, omode, 1, source, 1);
 
-               for (j=i+1; j<psl->sl_count; j++)
+               for (j = i+1; j < psl->sl_count; j++)
                        psl->sl_addr[j-1] = psl->sl_addr[j];
                psl->sl_count--;
                err = 0;
@@ -433,19 +435,19 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
                newpsl->sl_max = count;
                newpsl->sl_count = count - IP6_SFBLOCK;
                if (psl) {
-                       for (i=0; i<psl->sl_count; i++)
+                       for (i = 0; i < psl->sl_count; i++)
                                newpsl->sl_addr[i] = psl->sl_addr[i];
                        sock_kfree_s(sk, psl, IP6_SFLSIZE(psl->sl_max));
                }
                pmc->sflist = psl = newpsl;
        }
        rv = 1; /* > 0 for insert logic below if sl_count is 0 */
-       for (i=0; i<psl->sl_count; i++) {
+       for (i = 0; i < psl->sl_count; i++) {
                rv = !ipv6_addr_equal(&psl->sl_addr[i], source);
                if (rv == 0) /* There is an error in the address. */
                        goto done;
        }
-       for (j=psl->sl_count-1; j>=i; j--)
+       for (j = psl->sl_count-1; j >= i; j--)
                psl->sl_addr[j+1] = psl->sl_addr[j];
        psl->sl_addr[i] = *source;
        psl->sl_count++;
@@ -514,7 +516,7 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf)
                        goto done;
                }
                newpsl->sl_max = newpsl->sl_count = gsf->gf_numsrc;
-               for (i=0; i<newpsl->sl_count; ++i) {
+               for (i = 0; i < newpsl->sl_count; ++i) {
                        struct sockaddr_in6 *psin6;
 
                        psin6 = (struct sockaddr_in6 *)&gsf->gf_slist[i];
@@ -606,7 +608,7 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
         * on ipv6_sk_mc_lock and a write lock on pmc->sflock. We
         * have the socket lock, so reading here is safe.
         */
-       for (i=0; i<copycount; i++) {
+       for (i = 0; i < copycount; i++) {
                struct sockaddr_in6 *psin6;
                struct sockaddr_storage ss;
 
@@ -648,7 +650,7 @@ bool inet6_mc_check(struct sock *sk, const struct in6_addr *mc_addr,
        } else {
                int i;
 
-               for (i=0; i<psl->sl_count; i++) {
+               for (i = 0; i < psl->sl_count; i++) {
                        if (ipv6_addr_equal(&psl->sl_addr[i], src_addr))
                                break;
                }
@@ -762,7 +764,7 @@ static void mld_add_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im)
                pmc->mca_tomb = im->mca_tomb;
                pmc->mca_sources = im->mca_sources;
                im->mca_tomb = im->mca_sources = NULL;
-               for (psf=pmc->mca_sources; psf; psf=psf->sf_next)
+               for (psf = pmc->mca_sources; psf; psf = psf->sf_next)
                        psf->sf_crcount = pmc->mca_crcount;
        }
        spin_unlock_bh(&im->mca_lock);
@@ -780,7 +782,7 @@ static void mld_del_delrec(struct inet6_dev *idev, const struct in6_addr *pmca)
 
        spin_lock_bh(&idev->mc_lock);
        pmc_prev = NULL;
-       for (pmc=idev->mc_tomb; pmc; pmc=pmc->next) {
+       for (pmc = idev->mc_tomb; pmc; pmc = pmc->next) {
                if (ipv6_addr_equal(&pmc->mca_addr, pmca))
                        break;
                pmc_prev = pmc;
@@ -794,7 +796,7 @@ static void mld_del_delrec(struct inet6_dev *idev, const struct in6_addr *pmca)
        spin_unlock_bh(&idev->mc_lock);
 
        if (pmc) {
-               for (psf=pmc->mca_tomb; psf; psf=psf_next) {
+               for (psf = pmc->mca_tomb; psf; psf = psf_next) {
                        psf_next = psf->sf_next;
                        kfree(psf);
                }
@@ -821,14 +823,14 @@ static void mld_clear_delrec(struct inet6_dev *idev)
 
        /* clear dead sources, too */
        read_lock_bh(&idev->lock);
-       for (pmc=idev->mc_list; pmc; pmc=pmc->next) {
+       for (pmc = idev->mc_list; pmc; pmc = pmc->next) {
                struct ip6_sf_list *psf, *psf_next;
 
                spin_lock_bh(&pmc->mca_lock);
                psf = pmc->mca_tomb;
                pmc->mca_tomb = NULL;
                spin_unlock_bh(&pmc->mca_lock);
-               for (; psf; psf=psf_next) {
+               for (; psf; psf = psf_next) {
                        psf_next = psf->sf_next;
                        kfree(psf);
                }
@@ -845,6 +847,8 @@ int ipv6_dev_mc_inc(struct net_device *dev, const struct in6_addr *addr)
        struct ifmcaddr6 *mc;
        struct inet6_dev *idev;
 
+       ASSERT_RTNL();
+
        /* we need to take a reference on idev */
        idev = in6_dev_get(dev);
 
@@ -916,8 +920,10 @@ int __ipv6_dev_mc_dec(struct inet6_dev *idev, const struct in6_addr *addr)
 {
        struct ifmcaddr6 *ma, **map;
 
+       ASSERT_RTNL();
+
        write_lock_bh(&idev->lock);
-       for (map = &idev->mc_list; (ma=*map) != NULL; map = &ma->next) {
+       for (map = &idev->mc_list; (ma = *map) != NULL; map = &ma->next) {
                if (ipv6_addr_equal(&ma->mca_addr, addr)) {
                        if (--ma->mca_users == 0) {
                                *map = ma->next;
@@ -968,7 +974,7 @@ bool ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group,
        idev = __in6_dev_get(dev);
        if (idev) {
                read_lock_bh(&idev->lock);
-               for (mc = idev->mc_list; mc; mc=mc->next) {
+               for (mc = idev->mc_list; mc; mc = mc->next) {
                        if (ipv6_addr_equal(&mc->mca_addr, group))
                                break;
                }
@@ -977,7 +983,7 @@ bool ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group,
                                struct ip6_sf_list *psf;
 
                                spin_lock_bh(&mc->mca_lock);
-                               for (psf=mc->mca_sources;psf;psf=psf->sf_next) {
+                               for (psf = mc->mca_sources; psf; psf = psf->sf_next) {
                                        if (ipv6_addr_equal(&psf->sf_addr, src_addr))
                                                break;
                                }
@@ -986,7 +992,7 @@ bool ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group,
                                                psf->sf_count[MCAST_EXCLUDE] !=
                                                mc->mca_sfcount[MCAST_EXCLUDE];
                                else
-                                       rv = mc->mca_sfcount[MCAST_EXCLUDE] !=0;
+                                       rv = mc->mca_sfcount[MCAST_EXCLUDE] != 0;
                                spin_unlock_bh(&mc->mca_lock);
                        } else
                                rv = true; /* don't filter unspecified source */
@@ -1077,10 +1083,10 @@ static bool mld_xmarksources(struct ifmcaddr6 *pmc, int nsrcs,
        int i, scount;
 
        scount = 0;
-       for (psf=pmc->mca_sources; psf; psf=psf->sf_next) {
+       for (psf = pmc->mca_sources; psf; psf = psf->sf_next) {
                if (scount == nsrcs)
                        break;
-               for (i=0; i<nsrcs; i++) {
+               for (i = 0; i < nsrcs; i++) {
                        /* skip inactive filters */
                        if (psf->sf_count[MCAST_INCLUDE] ||
                            pmc->mca_sfcount[MCAST_EXCLUDE] !=
@@ -1110,10 +1116,10 @@ static bool mld_marksources(struct ifmcaddr6 *pmc, int nsrcs,
        /* mark INCLUDE-mode sources */
 
        scount = 0;
-       for (psf=pmc->mca_sources; psf; psf=psf->sf_next) {
+       for (psf = pmc->mca_sources; psf; psf = psf->sf_next) {
                if (scount == nsrcs)
                        break;
-               for (i=0; i<nsrcs; i++) {
+               for (i = 0; i < nsrcs; i++) {
                        if (ipv6_addr_equal(&srcs[i], &psf->sf_addr)) {
                                psf->sf_gsresp = 1;
                                scount++;
@@ -1191,15 +1197,16 @@ static void mld_update_qrv(struct inet6_dev *idev,
         * and SHOULD NOT be one. Catch this here if we ever run
         * into such a case in future.
         */
+       const int min_qrv = min(MLD_QRV_DEFAULT, sysctl_mld_qrv);
        WARN_ON(idev->mc_qrv == 0);
 
        if (mlh2->mld2q_qrv > 0)
                idev->mc_qrv = mlh2->mld2q_qrv;
 
-       if (unlikely(idev->mc_qrv < 2)) {
+       if (unlikely(idev->mc_qrv < min_qrv)) {
                net_warn_ratelimited("IPv6: MLD: clamping QRV from %u to %u!\n",
-                                    idev->mc_qrv, MLD_QRV_DEFAULT);
-               idev->mc_qrv = MLD_QRV_DEFAULT;
+                                    idev->mc_qrv, min_qrv);
+               idev->mc_qrv = min_qrv;
        }
 }
 
@@ -1364,13 +1371,13 @@ int igmp6_event_query(struct sk_buff *skb)
 
        read_lock_bh(&idev->lock);
        if (group_type == IPV6_ADDR_ANY) {
-               for (ma = idev->mc_list; ma; ma=ma->next) {
+               for (ma = idev->mc_list; ma; ma = ma->next) {
                        spin_lock_bh(&ma->mca_lock);
                        igmp6_group_queried(ma, max_delay);
                        spin_unlock_bh(&ma->mca_lock);
                }
        } else {
-               for (ma = idev->mc_list; ma; ma=ma->next) {
+               for (ma = idev->mc_list; ma; ma = ma->next) {
                        if (!ipv6_addr_equal(group, &ma->mca_addr))
                                continue;
                        spin_lock_bh(&ma->mca_lock);
@@ -1434,7 +1441,7 @@ int igmp6_event_report(struct sk_buff *skb)
         */
 
        read_lock_bh(&idev->lock);
-       for (ma = idev->mc_list; ma; ma=ma->next) {
+       for (ma = idev->mc_list; ma; ma = ma->next) {
                if (ipv6_addr_equal(&ma->mca_addr, &mld->mld_mca)) {
                        spin_lock(&ma->mca_lock);
                        if (del_timer(&ma->mca_timer))
@@ -1498,7 +1505,7 @@ mld_scount(struct ifmcaddr6 *pmc, int type, int gdeleted, int sdeleted)
        struct ip6_sf_list *psf;
        int scount = 0;
 
-       for (psf=pmc->mca_sources; psf; psf=psf->sf_next) {
+       for (psf = pmc->mca_sources; psf; psf = psf->sf_next) {
                if (!is_in(pmc, psf, type, gdeleted, sdeleted))
                        continue;
                scount++;
@@ -1712,7 +1719,7 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc,
        }
        first = 1;
        psf_prev = NULL;
-       for (psf=*psf_list; psf; psf=psf_next) {
+       for (psf = *psf_list; psf; psf = psf_next) {
                struct in6_addr *psrc;
 
                psf_next = psf->sf_next;
@@ -1791,7 +1798,7 @@ static void mld_send_report(struct inet6_dev *idev, struct ifmcaddr6 *pmc)
 
        read_lock_bh(&idev->lock);
        if (!pmc) {
-               for (pmc=idev->mc_list; pmc; pmc=pmc->next) {
+               for (pmc = idev->mc_list; pmc; pmc = pmc->next) {
                        if (pmc->mca_flags & MAF_NOREPORT)
                                continue;
                        spin_lock_bh(&pmc->mca_lock);
@@ -1824,7 +1831,7 @@ static void mld_clear_zeros(struct ip6_sf_list **ppsf)
        struct ip6_sf_list *psf_prev, *psf_next, *psf;
 
        psf_prev = NULL;
-       for (psf=*ppsf; psf; psf = psf_next) {
+       for (psf = *ppsf; psf; psf = psf_next) {
                psf_next = psf->sf_next;
                if (psf->sf_crcount == 0) {
                        if (psf_prev)
@@ -1848,7 +1855,7 @@ static void mld_send_cr(struct inet6_dev *idev)
 
        /* deleted MCA's */
        pmc_prev = NULL;
-       for (pmc=idev->mc_tomb; pmc; pmc=pmc_next) {
+       for (pmc = idev->mc_tomb; pmc; pmc = pmc_next) {
                pmc_next = pmc->next;
                if (pmc->mca_sfmode == MCAST_INCLUDE) {
                        type = MLD2_BLOCK_OLD_SOURCES;
@@ -1881,7 +1888,7 @@ static void mld_send_cr(struct inet6_dev *idev)
        spin_unlock(&idev->mc_lock);
 
        /* change recs */
-       for (pmc=idev->mc_list; pmc; pmc=pmc->next) {
+       for (pmc = idev->mc_list; pmc; pmc = pmc->next) {
                spin_lock_bh(&pmc->mca_lock);
                if (pmc->mca_sfcount[MCAST_EXCLUDE]) {
                        type = MLD2_BLOCK_OLD_SOURCES;
@@ -2018,7 +2025,7 @@ static void mld_send_initial_cr(struct inet6_dev *idev)
 
        skb = NULL;
        read_lock_bh(&idev->lock);
-       for (pmc=idev->mc_list; pmc; pmc=pmc->next) {
+       for (pmc = idev->mc_list; pmc; pmc = pmc->next) {
                spin_lock_bh(&pmc->mca_lock);
                if (pmc->mca_sfcount[MCAST_EXCLUDE])
                        type = MLD2_CHANGE_TO_EXCLUDE;
@@ -2063,7 +2070,7 @@ static int ip6_mc_del1_src(struct ifmcaddr6 *pmc, int sfmode,
        int rv = 0;
 
        psf_prev = NULL;
-       for (psf=pmc->mca_sources; psf; psf=psf->sf_next) {
+       for (psf = pmc->mca_sources; psf; psf = psf->sf_next) {
                if (ipv6_addr_equal(&psf->sf_addr, psfsrc))
                        break;
                psf_prev = psf;
@@ -2104,7 +2111,7 @@ static int ip6_mc_del_src(struct inet6_dev *idev, const struct in6_addr *pmca,
        if (!idev)
                return -ENODEV;
        read_lock_bh(&idev->lock);
-       for (pmc=idev->mc_list; pmc; pmc=pmc->next) {
+       for (pmc = idev->mc_list; pmc; pmc = pmc->next) {
                if (ipv6_addr_equal(pmca, &pmc->mca_addr))
                        break;
        }
@@ -2124,7 +2131,7 @@ static int ip6_mc_del_src(struct inet6_dev *idev, const struct in6_addr *pmca,
                pmc->mca_sfcount[sfmode]--;
        }
        err = 0;
-       for (i=0; i<sfcount; i++) {
+       for (i = 0; i < sfcount; i++) {
                int rv = ip6_mc_del1_src(pmc, sfmode, &psfsrc[i]);
 
                changerec |= rv > 0;
@@ -2140,7 +2147,7 @@ static int ip6_mc_del_src(struct inet6_dev *idev, const struct in6_addr *pmca,
                pmc->mca_sfmode = MCAST_INCLUDE;
                pmc->mca_crcount = idev->mc_qrv;
                idev->mc_ifc_count = pmc->mca_crcount;
-               for (psf=pmc->mca_sources; psf; psf = psf->sf_next)
+               for (psf = pmc->mca_sources; psf; psf = psf->sf_next)
                        psf->sf_crcount = 0;
                mld_ifc_event(pmc->idev);
        } else if (sf_setstate(pmc) || changerec)
@@ -2159,7 +2166,7 @@ static int ip6_mc_add1_src(struct ifmcaddr6 *pmc, int sfmode,
        struct ip6_sf_list *psf, *psf_prev;
 
        psf_prev = NULL;
-       for (psf=pmc->mca_sources; psf; psf=psf->sf_next) {
+       for (psf = pmc->mca_sources; psf; psf = psf->sf_next) {
                if (ipv6_addr_equal(&psf->sf_addr, psfsrc))
                        break;
                psf_prev = psf;
@@ -2184,7 +2191,7 @@ static void sf_markstate(struct ifmcaddr6 *pmc)
        struct ip6_sf_list *psf;
        int mca_xcount = pmc->mca_sfcount[MCAST_EXCLUDE];
 
-       for (psf=pmc->mca_sources; psf; psf=psf->sf_next)
+       for (psf = pmc->mca_sources; psf; psf = psf->sf_next)
                if (pmc->mca_sfcount[MCAST_EXCLUDE]) {
                        psf->sf_oldin = mca_xcount ==
                                psf->sf_count[MCAST_EXCLUDE] &&
@@ -2201,7 +2208,7 @@ static int sf_setstate(struct ifmcaddr6 *pmc)
        int new_in, rv;
 
        rv = 0;
-       for (psf=pmc->mca_sources; psf; psf=psf->sf_next) {
+       for (psf = pmc->mca_sources; psf; psf = psf->sf_next) {
                if (pmc->mca_sfcount[MCAST_EXCLUDE]) {
                        new_in = mca_xcount == psf->sf_count[MCAST_EXCLUDE] &&
                                !psf->sf_count[MCAST_INCLUDE];
@@ -2211,8 +2218,8 @@ static int sf_setstate(struct ifmcaddr6 *pmc)
                        if (!psf->sf_oldin) {
                                struct ip6_sf_list *prev = NULL;
 
-                               for (dpsf=pmc->mca_tomb; dpsf;
-                                    dpsf=dpsf->sf_next) {
+                               for (dpsf = pmc->mca_tomb; dpsf;
+                                    dpsf = dpsf->sf_next) {
                                        if (ipv6_addr_equal(&dpsf->sf_addr,
                                            &psf->sf_addr))
                                                break;
@@ -2234,7 +2241,7 @@ static int sf_setstate(struct ifmcaddr6 *pmc)
                         * add or update "delete" records if an active filter
                         * is now inactive
                         */
-                       for (dpsf=pmc->mca_tomb; dpsf; dpsf=dpsf->sf_next)
+                       for (dpsf = pmc->mca_tomb; dpsf; dpsf = dpsf->sf_next)
                                if (ipv6_addr_equal(&dpsf->sf_addr,
                                    &psf->sf_addr))
                                        break;
@@ -2268,7 +2275,7 @@ static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *pmca,
        if (!idev)
                return -ENODEV;
        read_lock_bh(&idev->lock);
-       for (pmc=idev->mc_list; pmc; pmc=pmc->next) {
+       for (pmc = idev->mc_list; pmc; pmc = pmc->next) {
                if (ipv6_addr_equal(pmca, &pmc->mca_addr))
                        break;
        }
@@ -2284,7 +2291,7 @@ static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *pmca,
        if (!delta)
                pmc->mca_sfcount[sfmode]++;
        err = 0;
-       for (i=0; i<sfcount; i++) {
+       for (i = 0; i < sfcount; i++) {
                err = ip6_mc_add1_src(pmc, sfmode, &psfsrc[i]);
                if (err)
                        break;
@@ -2294,7 +2301,7 @@ static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *pmca,
 
                if (!delta)
                        pmc->mca_sfcount[sfmode]--;
-               for (j=0; j<i; j++)
+               for (j = 0; j < i; j++)
                        ip6_mc_del1_src(pmc, sfmode, &psfsrc[j]);
        } else if (isexclude != (pmc->mca_sfcount[MCAST_EXCLUDE] != 0)) {
                struct ip6_sf_list *psf;
@@ -2308,7 +2315,7 @@ static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *pmca,
 
                pmc->mca_crcount = idev->mc_qrv;
                idev->mc_ifc_count = pmc->mca_crcount;
-               for (psf=pmc->mca_sources; psf; psf = psf->sf_next)
+               for (psf = pmc->mca_sources; psf; psf = psf->sf_next)
                        psf->sf_crcount = 0;
                mld_ifc_event(idev);
        } else if (sf_setstate(pmc))
@@ -2322,12 +2329,12 @@ static void ip6_mc_clear_src(struct ifmcaddr6 *pmc)
 {
        struct ip6_sf_list *psf, *nextpsf;
 
-       for (psf=pmc->mca_tomb; psf; psf=nextpsf) {
+       for (psf = pmc->mca_tomb; psf; psf = nextpsf) {
                nextpsf = psf->sf_next;
                kfree(psf);
        }
        pmc->mca_tomb = NULL;
-       for (psf=pmc->mca_sources; psf; psf=nextpsf) {
+       for (psf = pmc->mca_sources; psf; psf = nextpsf) {
                nextpsf = psf->sf_next;
                kfree(psf);
        }
@@ -2471,13 +2478,21 @@ void ipv6_mc_down(struct inet6_dev *idev)
        mld_gq_stop_timer(idev);
        mld_dad_stop_timer(idev);
 
-       for (i = idev->mc_list; i; i=i->next)
+       for (i = idev->mc_list; i; i = i->next)
                igmp6_group_dropped(i);
        read_unlock_bh(&idev->lock);
 
        mld_clear_delrec(idev);
 }
 
+static void ipv6_mc_reset(struct inet6_dev *idev)
+{
+       idev->mc_qrv = sysctl_mld_qrv;
+       idev->mc_qi = MLD_QI_DEFAULT;
+       idev->mc_qri = MLD_QRI_DEFAULT;
+       idev->mc_v1_seen = 0;
+       idev->mc_maxdelay = unsolicited_report_interval(idev);
+}
 
 /* Device going up */
 
@@ -2488,7 +2503,8 @@ void ipv6_mc_up(struct inet6_dev *idev)
        /* Install multicast list, except for all-nodes (already installed) */
 
        read_lock_bh(&idev->lock);
-       for (i = idev->mc_list; i; i=i->next)
+       ipv6_mc_reset(idev);
+       for (i = idev->mc_list; i; i = i->next)
                igmp6_group_added(i);
        read_unlock_bh(&idev->lock);
 }
@@ -2508,13 +2524,7 @@ void ipv6_mc_init_dev(struct inet6_dev *idev)
                        (unsigned long)idev);
        setup_timer(&idev->mc_dad_timer, mld_dad_timer_expire,
                    (unsigned long)idev);
-
-       idev->mc_qrv = MLD_QRV_DEFAULT;
-       idev->mc_qi = MLD_QI_DEFAULT;
-       idev->mc_qri = MLD_QRI_DEFAULT;
-
-       idev->mc_maxdelay = unsolicited_report_interval(idev);
-       idev->mc_v1_seen = 0;
+       ipv6_mc_reset(idev);
        write_unlock_bh(&idev->lock);
 }
 
index db9b6cbc9db3905695888343912be7dfd06af6f2..f61429d391d32693f3fb92fd75c630c01520f776 100644 (file)
@@ -336,11 +336,10 @@ static void mip6_destopt_destroy(struct xfrm_state *x)
 {
 }
 
-static const struct xfrm_type mip6_destopt_type =
-{
+static const struct xfrm_type mip6_destopt_type = {
        .description    = "MIP6DESTOPT",
        .owner          = THIS_MODULE,
-       .proto          = IPPROTO_DSTOPTS,
+       .proto          = IPPROTO_DSTOPTS,
        .flags          = XFRM_TYPE_NON_FRAGMENT | XFRM_TYPE_LOCAL_COADDR,
        .init_state     = mip6_destopt_init_state,
        .destructor     = mip6_destopt_destroy,
@@ -469,11 +468,10 @@ static void mip6_rthdr_destroy(struct xfrm_state *x)
 {
 }
 
-static const struct xfrm_type mip6_rthdr_type =
-{
+static const struct xfrm_type mip6_rthdr_type = {
        .description    = "MIP6RT",
        .owner          = THIS_MODULE,
-       .proto          = IPPROTO_ROUTING,
+       .proto          = IPPROTO_ROUTING,
        .flags          = XFRM_TYPE_NON_FRAGMENT | XFRM_TYPE_REMOTE_COADDR,
        .init_state     = mip6_rthdr_init_state,
        .destructor     = mip6_rthdr_destroy,
index 339078f95d1b6b955d29f094cf281f7835096f9c..4cb45c1079a29f4b7b59201e829905a5c65ac9fe 100644 (file)
@@ -175,7 +175,7 @@ static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur,
        type = cur->nd_opt_type;
        do {
                cur = ((void *)cur) + (cur->nd_opt_len << 3);
-       } while(cur < end && cur->nd_opt_type != type);
+       } while (cur < end && cur->nd_opt_type != type);
        return cur <= end && cur->nd_opt_type == type ? cur : NULL;
 }
 
@@ -192,7 +192,7 @@ static struct nd_opt_hdr *ndisc_next_useropt(struct nd_opt_hdr *cur,
                return NULL;
        do {
                cur = ((void *)cur) + (cur->nd_opt_len << 3);
-       } while(cur < end && !ndisc_is_useropt(cur));
+       } while (cur < end && !ndisc_is_useropt(cur));
        return cur <= end && ndisc_is_useropt(cur) ? cur : NULL;
 }
 
@@ -284,7 +284,6 @@ int ndisc_mc_map(const struct in6_addr *addr, char *buf, struct net_device *dev,
        }
        return -EINVAL;
 }
-
 EXPORT_SYMBOL(ndisc_mc_map);
 
 static u32 ndisc_hash(const void *pkey,
@@ -296,7 +295,7 @@ static u32 ndisc_hash(const void *pkey,
 
 static int ndisc_constructor(struct neighbour *neigh)
 {
-       struct in6_addr *addr = (struct in6_addr*)&neigh->primary_key;
+       struct in6_addr *addr = (struct in6_addr *)&neigh->primary_key;
        struct net_device *dev = neigh->dev;
        struct inet6_dev *in6_dev;
        struct neigh_parms *parms;
@@ -344,7 +343,7 @@ static int ndisc_constructor(struct neighbour *neigh)
 
 static int pndisc_constructor(struct pneigh_entry *n)
 {
-       struct in6_addr *addr = (struct in6_addr*)&n->key;
+       struct in6_addr *addr = (struct in6_addr *)&n->key;
        struct in6_addr maddr;
        struct net_device *dev = n->dev;
 
@@ -357,7 +356,7 @@ static int pndisc_constructor(struct pneigh_entry *n)
 
 static void pndisc_destructor(struct pneigh_entry *n)
 {
-       struct in6_addr *addr = (struct in6_addr*)&n->key;
+       struct in6_addr *addr = (struct in6_addr *)&n->key;
        struct in6_addr maddr;
        struct net_device *dev = n->dev;
 
@@ -1065,7 +1064,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)
        int optlen;
        unsigned int pref = 0;
 
-       __u8 * opt = (__u8 *)(ra_msg + 1);
+       __u8 *opt = (__u8 *)(ra_msg + 1);
 
        optlen = (skb_tail_pointer(skb) - skb_transport_header(skb)) -
                sizeof(struct ra_msg);
@@ -1319,7 +1318,7 @@ skip_linkparms:
                                continue;
                        if (ri->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen)
                                continue;
-                       rt6_route_rcv(skb->dev, (u8*)p, (p->nd_opt_len) << 3,
+                       rt6_route_rcv(skb->dev, (u8 *)p, (p->nd_opt_len) << 3,
                                      &ipv6_hdr(skb)->saddr);
                }
        }
@@ -1352,7 +1351,7 @@ skip_routeinfo:
                __be32 n;
                u32 mtu;
 
-               memcpy(&n, ((u8*)(ndopts.nd_opts_mtu+1))+2, sizeof(mtu));
+               memcpy(&n, ((u8 *)(ndopts.nd_opts_mtu+1))+2, sizeof(mtu));
                mtu = ntohl(n);
 
                if (mtu < IPV6_MIN_MTU || mtu > skb->dev->mtu) {
index 24c535f66df02528a96a6db4fc2d931e82e98a37..a8f25306a46a2457d07fb9ce12a90649d9dcfec7 100644 (file)
@@ -57,9 +57,19 @@ config NFT_REJECT_IPV6
 
 config NF_LOG_IPV6
        tristate "IPv6 packet logging"
-       depends on NETFILTER_ADVANCED
+       default m if NETFILTER_ADVANCED=n
        select NF_LOG_COMMON
 
+config NF_NAT_IPV6
+       tristate "IPv6 NAT"
+       depends on NF_CONNTRACK_IPV6
+       depends on NETFILTER_ADVANCED
+       select NF_NAT
+       help
+         The IPv6 NAT option allows masquerading, port forwarding and other
+         forms of full Network Address Port Translation. This can be
+         controlled by iptables or nft.
+
 config IP6_NF_IPTABLES
        tristate "IP6 tables support (required for filtering)"
        depends on INET && IPV6
@@ -232,19 +242,21 @@ config IP6_NF_SECURITY
 
          If unsure, say N.
 
-config NF_NAT_IPV6
-       tristate "IPv6 NAT"
+config IP6_NF_NAT
+       tristate "ip6tables NAT support"
        depends on NF_CONNTRACK_IPV6
        depends on NETFILTER_ADVANCED
        select NF_NAT
+       select NF_NAT_IPV6
+       select NETFILTER_XT_NAT
        help
-         The IPv6 NAT option allows masquerading, port forwarding and other
-         forms of full Network Address Port Translation. It is controlled by
-         the `nat' table in ip6tables, see the man page for ip6tables(8).
+         This enables the `nat' table in ip6tables. This allows masquerading,
+         port forwarding and other forms of full Network Address Port
+         Translation.
 
          To compile it as a module, choose M here.  If unsure, say N.
 
-if NF_NAT_IPV6
+if IP6_NF_NAT
 
 config NF_NAT_MASQUERADE_IPV6
        tristate "IPv6 masquerade support"
@@ -278,7 +290,7 @@ config IP6_NF_TARGET_NPT
 
          To compile it as a module, choose M here.  If unsure, say N.
 
-endif # NF_NAT_IPV6
+endif # IP6_NF_NAT
 
 endif # IP6_NF_IPTABLES
 
index 482c4dff273f5f54d87edd2726957fce973b5ad1..0f7e5b3f328dd8da268d3c200e9edb53a490cf45 100644 (file)
@@ -8,7 +8,7 @@ obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o
 obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o
 obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o
 obj-$(CONFIG_IP6_NF_SECURITY) += ip6table_security.o
-obj-$(CONFIG_NF_NAT_IPV6) += ip6table_nat.o
+obj-$(CONFIG_IP6_NF_NAT) += ip6table_nat.o
 
 # objects for l3 independent conntrack
 nf_conntrack_ipv6-y  :=  nf_conntrack_l3proto_ipv6.o nf_conntrack_proto_icmpv6.o
index 5ec867e4a8b74fb23d8fdd2bcf9e0dce52f94455..fc24c390af0541050782c76434ccbbf9e00c24f0 100644 (file)
@@ -35,7 +35,7 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
                        if (found_rhdr)
                                return offset;
                        break;
-               default :
+               default:
                        return offset;
                }
 
index 2d6f860e5c1e77cb087b2220ba2db9592a770159..1752cd0b48820367ad64cd926d8ea16a6c69341a 100644 (file)
@@ -8,7 +8,7 @@
  *             except it reports the sockets in the INET6 address family.
  *
  * Authors:    David S. Miller (davem@caip.rutgers.edu)
- *             YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
+ *             YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
  *
  *             This program is free software; you can redistribute it and/or
  *             modify it under the terms of the GNU General Public License
index 39d44226e402473ed03058f6945111f02abeb146..896af8807979fad382ba65724ccad0bf040c992f 100644 (file)
@@ -889,7 +889,7 @@ back_from_confirm:
        else {
                lock_sock(sk);
                err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov,
-                       len, 0, hlimit, tclass, opt, &fl6, (struct rt6_info*)dst,
+                       len, 0, hlimit, tclass, opt, &fl6, (struct rt6_info *)dst,
                        msg->msg_flags, dontfrag);
 
                if (err)
@@ -902,7 +902,7 @@ done:
        dst_release(dst);
 out:
        fl6_sock_release(flowlabel);
-       return err<0?err:len;
+       return err < 0 ? err : len;
 do_confirm:
        dst_confirm(dst);
        if (!(msg->msg_flags & MSG_PROBE) || len)
@@ -1045,7 +1045,7 @@ static int do_rawv6_getsockopt(struct sock *sk, int level, int optname,
        struct raw6_sock *rp = raw6_sk(sk);
        int val, len;
 
-       if (get_user(len,optlen))
+       if (get_user(len, optlen))
                return -EFAULT;
 
        switch (optname) {
@@ -1069,7 +1069,7 @@ static int do_rawv6_getsockopt(struct sock *sk, int level, int optname,
 
        if (put_user(len, optlen))
                return -EFAULT;
-       if (copy_to_user(optval,&val,len))
+       if (copy_to_user(optval, &val, len))
                return -EFAULT;
        return 0;
 }
index c6557d9f7808c42e686582f31e8cc535a7067f3f..1a157ca2ebc18c5a12519adb9eacd30d508722eb 100644 (file)
 
 static const char ip6_frag_cache_name[] = "ip6-frags";
 
-struct ip6frag_skb_cb
-{
+struct ip6frag_skb_cb {
        struct inet6_skb_parm   h;
        int                     offset;
 };
 
-#define FRAG6_CB(skb)  ((struct ip6frag_skb_cb*)((skb)->cb))
+#define FRAG6_CB(skb)  ((struct ip6frag_skb_cb *)((skb)->cb))
 
 static inline u8 ip6_frag_ecn(const struct ipv6hdr *ipv6h)
 {
@@ -289,7 +288,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
                goto found;
        }
        prev = NULL;
-       for(next = fq->q.fragments; next != NULL; next = next->next) {
+       for (next = fq->q.fragments; next != NULL; next = next->next) {
                if (FRAG6_CB(next)->offset >= offset)
                        break;  /* bingo! */
                prev = next;
@@ -529,7 +528,7 @@ static int ipv6_frag_rcv(struct sk_buff *skb)
        IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_REASMREQDS);
 
        /* Jumbo payload inhibits frag. header */
-       if (hdr->payload_len==0)
+       if (hdr->payload_len == 0)
                goto fail_hdr;
 
        if (!pskb_may_pull(skb, (skb_transport_offset(skb) +
@@ -575,8 +574,7 @@ fail_hdr:
        return -1;
 }
 
-static const struct inet6_protocol frag_protocol =
-{
+static const struct inet6_protocol frag_protocol = {
        .handler        =       ipv6_frag_rcv,
        .flags          =       INET6_PROTO_NOPOLICY,
 };
index f23fbd28a501ed5c3438abb7f1cbbec85233688b..f74b0417bd60c4ada1d0e582dfbb1733fe750d8d 100644 (file)
@@ -813,7 +813,7 @@ out:
 
 }
 
-struct dst_entry * ip6_route_lookup(struct net *net, struct flowi6 *fl6,
+struct dst_entry *ip6_route_lookup(struct net *net, struct flowi6 *fl6,
                                    int flags)
 {
        return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_lookup);
@@ -843,7 +843,6 @@ struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr,
 
        return NULL;
 }
-
 EXPORT_SYMBOL(rt6_lookup);
 
 /* ip6_ins_rt is called with FREE table->tb6_lock.
@@ -1024,7 +1023,7 @@ static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table
        return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, flags);
 }
 
-struct dst_entry * ip6_route_output(struct net *net, const struct sock *sk,
+struct dst_entry *ip6_route_output(struct net *net, const struct sock *sk,
                                    struct flowi6 *fl6)
 {
        int flags = 0;
@@ -1041,7 +1040,6 @@ struct dst_entry * ip6_route_output(struct net *net, const struct sock *sk,
 
        return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_output);
 }
-
 EXPORT_SYMBOL(ip6_route_output);
 
 struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig)
@@ -1149,7 +1147,7 @@ static void ip6_link_failure(struct sk_buff *skb)
 static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
                               struct sk_buff *skb, u32 mtu)
 {
-       struct rt6_info *rt6 = (struct rt6_info*)dst;
+       struct rt6_info *rt6 = (struct rt6_info *)dst;
 
        dst_confirm(dst);
        if (mtu < dst_mtu(dst) && rt6->rt6i_dst.plen == 128) {
@@ -1924,7 +1922,7 @@ static struct rt6_info *rt6_get_route_info(struct net *net,
                return NULL;
 
        read_lock_bh(&table->tb6_lock);
-       fn = fib6_locate(&table->tb6_root, prefix ,prefixlen, NULL, 0);
+       fn = fib6_locate(&table->tb6_root, prefixprefixlen, NULL, 0);
        if (!fn)
                goto out;
 
@@ -1983,7 +1981,7 @@ struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_dev
                return NULL;
 
        read_lock_bh(&table->tb6_lock);
-       for (rt = table->tb6_root.leaf; rt; rt=rt->dst.rt6_next) {
+       for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
                if (dev == rt->dst.dev &&
                    ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&
                    ipv6_addr_equal(&rt->rt6i_gateway, addr))
@@ -2068,7 +2066,7 @@ int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg)
        struct in6_rtmsg rtmsg;
        int err;
 
-       switch(cmd) {
+       switch (cmd) {
        case SIOCADDRT:         /* Add a route */
        case SIOCDELRT:         /* Delete a route */
                if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
@@ -2191,7 +2189,7 @@ int ip6_route_get_saddr(struct net *net,
                        unsigned int prefs,
                        struct in6_addr *saddr)
 {
-       struct inet6_dev *idev = ip6_dst_idev((struct dst_entry*)rt);
+       struct inet6_dev *idev = ip6_dst_idev((struct dst_entry *)rt);
        int err = 0;
        if (rt->rt6i_prefsrc.plen)
                *saddr = rt->rt6i_prefsrc.addr;
@@ -2486,7 +2484,7 @@ beginning:
        return last_err;
 }
 
-static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdrnlh)
+static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh)
 {
        struct fib6_config cfg;
        int err;
@@ -2501,7 +2499,7 @@ static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh)
                return ip6_route_del(&cfg);
 }
 
-static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdrnlh)
+static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh)
 {
        struct fib6_config cfg;
        int err;
@@ -2693,7 +2691,7 @@ int rt6_dump_route(struct rt6_info *rt, void *p_arg)
                     prefix, 0, NLM_F_MULTI);
 }
 
-static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdrnlh)
+static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh)
 {
        struct net *net = sock_net(in_skb->sk);
        struct nlattr *tb[RTA_MAX+1];
index 6163f851dc014ebd205211829214ce4d0bbc332b..86e3fa81f85eba7928a3c68d0c997e190c79543e 100644 (file)
@@ -812,9 +812,9 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
        const struct ipv6hdr *iph6 = ipv6_hdr(skb);
        u8     tos = tunnel->parms.iph.tos;
        __be16 df = tiph->frag_off;
-       struct rtable *rt;                      /* Route to the other host */
-       struct net_device *tdev;                /* Device to other host */
-       unsigned int max_headroom;              /* The extra header space needed */
+       struct rtable *rt;              /* Route to the other host */
+       struct net_device *tdev;        /* Device to other host */
+       unsigned int max_headroom;      /* The extra header space needed */
        __be32 dst = tiph->daddr;
        struct flowi4 fl4;
        int    mtu;
@@ -1123,7 +1123,7 @@ static int ipip6_tunnel_update_6rd(struct ip_tunnel *t,
 #endif
 
 static int
-ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
+ipip6_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
        int err = 0;
        struct ip_tunnel_parm p;
@@ -1339,10 +1339,10 @@ static void ipip6_dev_free(struct net_device *dev)
 static void ipip6_tunnel_setup(struct net_device *dev)
 {
        dev->netdev_ops         = &ipip6_netdev_ops;
-       dev->destructor         = ipip6_dev_free;
+       dev->destructor         = ipip6_dev_free;
 
        dev->type               = ARPHRD_SIT;
-       dev->hard_header_len    = LL_MAX_HEADER + sizeof(struct iphdr);
+       dev->hard_header_len    = LL_MAX_HEADER + sizeof(struct iphdr);
        dev->mtu                = ETH_DATA_LEN - sizeof(struct iphdr);
        dev->flags              = IFF_NOARP;
        dev->priv_flags        &= ~IFF_XMIT_DST_RELEASE;
index 83cea1d39466affce703d7c1b737a386bf3faecf..c643dc907ce773badc1c8ec9029b20909c21698a 100644 (file)
@@ -24,7 +24,7 @@
 #define COOKIEBITS 24  /* Upper bits store count */
 #define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1)
 
-static u32 syncookie6_secret[2][16-4+SHA_DIGEST_WORDS];
+static u32 syncookie6_secret[2][16-4+SHA_DIGEST_WORDS] __read_mostly;
 
 /* RFC 2460, Section 8.3:
  * [ipv6 tcp] MSS must be computed as the maximum packet size minus 60 [..]
index 0c56c93619e063710a8d32f3f9e15fd9cdb6453c..c5c10fafcfe2e068fe33adc8367206a16e40c7bf 100644 (file)
@@ -16,6 +16,8 @@
 #include <net/addrconf.h>
 #include <net/inet_frag.h>
 
+static int one = 1;
+
 static struct ctl_table ipv6_table_template[] = {
        {
                .procname       = "bindv6only",
@@ -63,6 +65,14 @@ static struct ctl_table ipv6_rotable[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec
        },
+       {
+               .procname       = "mld_qrv",
+               .data           = &sysctl_mld_qrv,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &one
+       },
        { }
 };
 
index 29964c3d363c8a0e741b01b9df32fce3cdd7a1ba..1835480336acb9344558ff5a71e037c8992204f1 100644 (file)
@@ -93,13 +93,16 @@ static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk,
 static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
 {
        struct dst_entry *dst = skb_dst(skb);
-       const struct rt6_info *rt = (const struct rt6_info *)dst;
 
-       dst_hold(dst);
-       sk->sk_rx_dst = dst;
-       inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
-       if (rt->rt6i_node)
-               inet6_sk(sk)->rx_dst_cookie = rt->rt6i_node->fn_sernum;
+       if (dst) {
+               const struct rt6_info *rt = (const struct rt6_info *)dst;
+
+               dst_hold(dst);
+               sk->sk_rx_dst = dst;
+               inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
+               if (rt->rt6i_node)
+                       inet6_sk(sk)->rx_dst_cookie = rt->rt6i_node->fn_sernum;
+       }
 }
 
 static void tcp_v6_hash(struct sock *sk)
@@ -738,7 +741,7 @@ static void tcp_v6_init_req(struct request_sock *req, struct sock *sk,
            ipv6_addr_type(&ireq->ir_v6_rmt_addr) & IPV6_ADDR_LINKLOCAL)
                ireq->ir_iif = inet6_iif(skb);
 
-       if (!TCP_SKB_CB(skb)->when &&
+       if (!TCP_SKB_CB(skb)->tcp_tw_isn &&
            (ipv6_opt_accepted(sk, skb) || np->rxopt.bits.rxinfo ||
             np->rxopt.bits.rxoinfo || np->rxopt.bits.rxhlim ||
             np->rxopt.bits.rxohlim || np->repflow)) {
@@ -1412,7 +1415,7 @@ static int tcp_v6_rcv(struct sk_buff *skb)
        TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
                                    skb->len - th->doff*4);
        TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
-       TCP_SKB_CB(skb)->when = 0;
+       TCP_SKB_CB(skb)->tcp_tw_isn = 0;
        TCP_SKB_CB(skb)->ip_dsfield = ipv6_get_dsfield(hdr);
        TCP_SKB_CB(skb)->sacked = 0;
 
index 01b0ff9a0c2c00d6734537254e2150edcbcb64d7..dbb3d9262bf66837a10e6ecc764dbcd0ea327264 100644 (file)
@@ -35,34 +35,14 @@ static int tcp_v6_gso_send_check(struct sk_buff *skb)
 static struct sk_buff **tcp6_gro_receive(struct sk_buff **head,
                                         struct sk_buff *skb)
 {
-       const struct ipv6hdr *iph = skb_gro_network_header(skb);
-       __wsum wsum;
-
        /* Don't bother verifying checksum if we're going to flush anyway. */
-       if (NAPI_GRO_CB(skb)->flush)
-               goto skip_csum;
-
-       wsum = NAPI_GRO_CB(skb)->csum;
-
-       switch (skb->ip_summed) {
-       case CHECKSUM_NONE:
-               wsum = skb_checksum(skb, skb_gro_offset(skb), skb_gro_len(skb),
-                                   wsum);
-
-               /* fall through */
-
-       case CHECKSUM_COMPLETE:
-               if (!tcp_v6_check(skb_gro_len(skb), &iph->saddr, &iph->daddr,
-                                 wsum)) {
-                       skb->ip_summed = CHECKSUM_UNNECESSARY;
-                       break;
-               }
-
+       if (!NAPI_GRO_CB(skb)->flush &&
+           skb_gro_checksum_validate(skb, IPPROTO_TCP,
+                                     ip6_gro_compute_pseudo)) {
                NAPI_GRO_CB(skb)->flush = 1;
                return NULL;
        }
 
-skip_csum:
        return tcp_gro_receive(head, skb);
 }
 
index 2c4e4c5c7614bf9ee864a99e095c7c17e46d9b57..3c758007b327decd0f1d950ae6cca928af052b05 100644 (file)
@@ -15,7 +15,7 @@
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  *
  * Authors     Mitsuru KANDA  <mk@linux-ipv6.org>
- *             YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
+ *             YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
  */
 
 #define pr_fmt(fmt) "IPv6: " fmt
@@ -64,7 +64,6 @@ err:
 
        return ret;
 }
-
 EXPORT_SYMBOL(xfrm6_tunnel_register);
 
 int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family)
@@ -92,7 +91,6 @@ int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family)
 
        return ret;
 }
-
 EXPORT_SYMBOL(xfrm6_tunnel_deregister);
 
 #define for_each_tunnel_rcu(head, handler)             \
index 4836af8f582d32d881f8697c1c92b6909e37ab27..f6ba535b6febe40aad990e7f9541446fc573d511 100644 (file)
@@ -243,7 +243,7 @@ begin:
                                goto exact_match;
                } else if (score == badness && reuseport) {
                        matches++;
-                       if (((u64)hash * matches) >> 32 == 0)
+                       if (reciprocal_scale(hash, matches) == 0)
                                result = sk;
                        hash = next_pseudo_random32(hash);
                }
@@ -323,7 +323,7 @@ begin:
                        }
                } else if (score == badness && reuseport) {
                        matches++;
-                       if (((u64)hash * matches) >> 32 == 0)
+                       if (reciprocal_scale(hash, matches) == 0)
                                result = sk;
                        hash = next_pseudo_random32(hash);
                }
@@ -373,8 +373,8 @@ EXPORT_SYMBOL_GPL(udp6_lib_lookup);
 
 
 /*
- *     This should be easy, if there is something there we
- *     return it, otherwise we block.
+ *     This should be easy, if there is something there we
+ *     return it, otherwise we block.
  */
 
 int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk,
@@ -530,7 +530,7 @@ void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
        const struct ipv6hdr *hdr = (const struct ipv6hdr *)skb->data;
        const struct in6_addr *saddr = &hdr->saddr;
        const struct in6_addr *daddr = &hdr->daddr;
-       struct udphdr *uh = (struct udphdr*)(skb->data+offset);
+       struct udphdr *uh = (struct udphdr *)(skb->data+offset);
        struct sock *sk;
        int err;
        struct net *net = dev_net(skb->dev);
@@ -596,7 +596,7 @@ static int __udpv6_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
 
 static __inline__ void udpv6_err(struct sk_buff *skb,
                                 struct inet6_skb_parm *opt, u8 type,
-                                u8 code, int offset, __be32 info     )
+                                u8 code, int offset, __be32 info)
 {
        __udp6_lib_err(skb, opt, type, code, offset, info, &udp_table);
 }
@@ -891,6 +891,10 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
                        goto csum_error;
                }
 
+               if (udp_sk(sk)->convert_csum && uh->check && !IS_UDPLITE(sk))
+                       skb_checksum_try_convert(skb, IPPROTO_UDP, uh->check,
+                                                ip6_compute_pseudo);
+
                ret = udpv6_queue_rcv_skb(sk, skb);
                sock_put(sk);
 
@@ -960,10 +964,10 @@ static void udp_v6_flush_pending_frames(struct sock *sk)
 }
 
 /**
- *     udp6_hwcsum_outgoing  -  handle outgoing HW checksumming
- *     @sk:    socket we are sending on
- *     @skb:   sk_buff containing the filled-in UDP header
- *             (checksum field must be zeroed out)
+ *     udp6_hwcsum_outgoing  -  handle outgoing HW checksumming
+ *     @sk:    socket we are sending on
+ *     @skb:   sk_buff containing the filled-in UDP header
+ *             (checksum field must be zeroed out)
  */
 static void udp6_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb,
                                 const struct in6_addr *saddr,
@@ -1294,7 +1298,7 @@ do_append_data:
        getfrag  =  is_udplite ?  udplite_getfrag : ip_generic_getfrag;
        err = ip6_append_data(sk, getfrag, msg->msg_iov, ulen,
                sizeof(struct udphdr), hlimit, tclass, opt, &fl6,
-               (struct rt6_info*)dst,
+               (struct rt6_info *)dst,
                corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags, dontfrag);
        if (err)
                udp_v6_flush_pending_frames(sk);
index 0ae3d98f83e00533c14e6f8c23ab78a5a6a72625..a1ad34b1c4ecd236bfd1d3536ccffe60013ca29b 100644 (file)
@@ -10,6 +10,7 @@
  *      UDPv6 GSO support
  */
 #include <linux/skbuff.h>
+#include <linux/netdevice.h>
 #include <net/protocol.h>
 #include <net/ipv6.h>
 #include <net/udp.h>
@@ -127,10 +128,52 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
 out:
        return segs;
 }
+
+static struct sk_buff **udp6_gro_receive(struct sk_buff **head,
+                                        struct sk_buff *skb)
+{
+       struct udphdr *uh = udp_gro_udphdr(skb);
+
+       if (unlikely(!uh))
+               goto flush;
+
+       /* Don't bother verifying checksum if we're going to flush anyway. */
+       if (!NAPI_GRO_CB(skb)->flush)
+               goto skip;
+
+       if (skb_gro_checksum_validate_zero_check(skb, IPPROTO_UDP, uh->check,
+                                                ip6_gro_compute_pseudo))
+               goto flush;
+       else if (uh->check)
+               skb_gro_checksum_try_convert(skb, IPPROTO_UDP, uh->check,
+                                            ip6_gro_compute_pseudo);
+
+skip:
+       return udp_gro_receive(head, skb, uh);
+
+flush:
+       NAPI_GRO_CB(skb)->flush = 1;
+       return NULL;
+}
+
+static int udp6_gro_complete(struct sk_buff *skb, int nhoff)
+{
+       const struct ipv6hdr *ipv6h = ipv6_hdr(skb);
+       struct udphdr *uh = (struct udphdr *)(skb->data + nhoff);
+
+       if (uh->check)
+               uh->check = ~udp_v6_check(skb->len - nhoff, &ipv6h->saddr,
+                                         &ipv6h->daddr, 0);
+
+       return udp_gro_complete(skb, nhoff);
+}
+
 static const struct net_offload udpv6_offload = {
        .callbacks = {
                .gso_send_check =       udp6_ufo_send_check,
                .gso_segment    =       udp6_ufo_fragment,
+               .gro_receive    =       udp6_gro_receive,
+               .gro_complete   =       udp6_gro_complete,
        },
 };
 
index f8c3cf842f534e3e87c35a1213afcb320880998b..f48fbe4d16f5f433c40cba8077663db77d2984d4 100644 (file)
@@ -3,8 +3,8 @@
  *
  * Authors:
  *     Mitsuru KANDA @USAGI
- *     Kazunori MIYAZAWA @USAGI
- *     Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+ *     Kazunori MIYAZAWA @USAGI
+ *     Kunihiro Ishiguro <kunihiro@ipinfusion.com>
  *     YOSHIFUJI Hideaki @USAGI
  *             IPv6 support
  */
@@ -52,7 +52,6 @@ int xfrm6_rcv(struct sk_buff *skb)
        return xfrm6_rcv_spi(skb, skb_network_header(skb)[IP6CB(skb)->nhoff],
                             0);
 }
-
 EXPORT_SYMBOL(xfrm6_rcv);
 
 int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
@@ -142,5 +141,4 @@ int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
 drop:
        return -1;
 }
-
 EXPORT_SYMBOL(xfrm6_input_addr);
index 433672d07d0b55e1e436be704780e8c6f5777447..ca3f29b98ae5d76b7e69c38f617362a90fd9fd04 100644 (file)
@@ -25,7 +25,6 @@ int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb,
 {
        return ip6_find_1stfragopt(skb, prevhdr);
 }
-
 EXPORT_SYMBOL(xfrm6_find_1stfragopt);
 
 static int xfrm6_local_dontfrag(struct sk_buff *skb)
index 2a0bbda2c76a99dfa687313d230595c251103b45..ac49f84fe2c34026b7af5392df06fc232ea3b9e1 100644 (file)
@@ -3,11 +3,11 @@
  *
  * Authors:
  *     Mitsuru KANDA @USAGI
- *     Kazunori MIYAZAWA @USAGI
- *     Kunihiro Ishiguro <kunihiro@ipinfusion.com>
- *             IPv6 support
- *     YOSHIFUJI Hideaki
- *             Split up af-specific portion
+ *     Kazunori MIYAZAWA @USAGI
+ *     Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+ *             IPv6 support
+ *     YOSHIFUJI Hideaki
+ *             Split up af-specific portion
  *
  */
 
@@ -84,7 +84,7 @@ static int xfrm6_init_path(struct xfrm_dst *path, struct dst_entry *dst,
                           int nfheader_len)
 {
        if (dst->ops->family == AF_INET6) {
-               struct rt6_info *rt = (struct rt6_info*)dst;
+               struct rt6_info *rt = (struct rt6_info *)dst;
                if (rt->rt6i_node)
                        path->path_cookie = rt->rt6i_node->fn_sernum;
        }
@@ -97,7 +97,7 @@ static int xfrm6_init_path(struct xfrm_dst *path, struct dst_entry *dst,
 static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
                          const struct flowi *fl)
 {
-       struct rt6_info *rt = (struct rt6_info*)xdst->route;
+       struct rt6_info *rt = (struct rt6_info *)xdst->route;
 
        xdst->u.dst.dev = dev;
        dev_hold(dev);
@@ -296,7 +296,7 @@ static struct xfrm_policy_afinfo xfrm6_policy_afinfo = {
        .family =               AF_INET6,
        .dst_ops =              &xfrm6_dst_ops,
        .dst_lookup =           xfrm6_dst_lookup,
-       .get_saddr =            xfrm6_get_saddr,
+       .get_saddr =            xfrm6_get_saddr,
        .decode_session =       _decode_session6,
        .get_tos =              xfrm6_get_tos,
        .init_dst =             xfrm6_init_dst,
@@ -319,9 +319,9 @@ static void xfrm6_policy_fini(void)
 static struct ctl_table xfrm6_policy_table[] = {
        {
                .procname       = "xfrm6_gc_thresh",
-               .data           = &init_net.xfrm.xfrm6_dst_ops.gc_thresh,
-               .maxlen         = sizeof(int),
-               .mode           = 0644,
+               .data           = &init_net.xfrm.xfrm6_dst_ops.gc_thresh,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
        { }
index 3fc970135fc66583e5842943246993da7e2b69b4..8a1f9c0d2a13b27ae0b67c9eacf802f30e656115 100644 (file)
@@ -3,11 +3,11 @@
  *
  * Authors:
  *     Mitsuru KANDA @USAGI
- *     Kazunori MIYAZAWA @USAGI
- *     Kunihiro Ishiguro <kunihiro@ipinfusion.com>
- *             IPv6 support
- *     YOSHIFUJI Hideaki @USAGI
- *             Split up af-specific portion
+ *     Kazunori MIYAZAWA @USAGI
+ *     Kunihiro Ishiguro <kunihiro@ipinfusion.com>
+ *             IPv6 support
+ *     YOSHIFUJI Hideaki @USAGI
+ *             Split up af-specific portion
  *
  */
 
@@ -45,10 +45,10 @@ xfrm6_init_temprop(struct xfrm_state *x, const struct xfrm_tmpl *tmpl,
                   const xfrm_address_t *daddr, const xfrm_address_t *saddr)
 {
        x->id = tmpl->id;
-       if (ipv6_addr_any((struct in6_addr*)&x->id.daddr))
+       if (ipv6_addr_any((struct in6_addr *)&x->id.daddr))
                memcpy(&x->id.daddr, daddr, sizeof(x->sel.daddr));
        memcpy(&x->props.saddr, &tmpl->saddr, sizeof(x->props.saddr));
-       if (ipv6_addr_any((struct in6_addr*)&x->props.saddr))
+       if (ipv6_addr_any((struct in6_addr *)&x->props.saddr))
                memcpy(&x->props.saddr, saddr, sizeof(x->props.saddr));
        x->props.mode = tmpl->mode;
        x->props.reqid = tmpl->reqid;
index 1c66465a42ddc09627dae47d4c6cbd40aa4fdc35..5743044cd660b8a8557d1a87c4ee35508ebff7e0 100644 (file)
@@ -15,7 +15,7 @@
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  *
  * Authors     Mitsuru KANDA  <mk@linux-ipv6.org>
- *             YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
+ *             YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
  *
  * Based on net/ipv4/xfrm4_tunnel.c
  *
@@ -110,7 +110,6 @@ __be32 xfrm6_tunnel_spi_lookup(struct net *net, const xfrm_address_t *saddr)
        rcu_read_unlock_bh();
        return htonl(spi);
 }
-
 EXPORT_SYMBOL(xfrm6_tunnel_spi_lookup);
 
 static int __xfrm6_tunnel_spi_check(struct net *net, u32 spi)
@@ -187,7 +186,6 @@ __be32 xfrm6_tunnel_alloc_spi(struct net *net, xfrm_address_t *saddr)
 
        return htonl(spi);
 }
-
 EXPORT_SYMBOL(xfrm6_tunnel_alloc_spi);
 
 static void x6spi_destroy_rcu(struct rcu_head *head)
index da787930df0ab643a81bfa1f3f554efb2cd41bee..2a6a1fdd62c059eb857312d10fee38fa1c6bc86f 100644 (file)
@@ -493,8 +493,8 @@ static void iucv_declare_cpu(void *data)
                        err = "Paging or storage error";
                        break;
                }
-               pr_warning("Defining an interrupt buffer on CPU %i"
-                          " failed with 0x%02x (%s)\n", cpu, rc, err);
+               pr_warn("Defining an interrupt buffer on CPU %i failed with 0x%02x (%s)\n",
+                       cpu, rc, err);
                return;
        }
 
@@ -1831,7 +1831,7 @@ static void iucv_external_interrupt(struct ext_code ext_code,
        BUG_ON(p->iptype  < 0x01 || p->iptype > 0x09);
        work = kmalloc(sizeof(struct iucv_irq_list), GFP_ATOMIC);
        if (!work) {
-               pr_warning("iucv_external_interrupt: out of memory\n");
+               pr_warn("iucv_external_interrupt: out of memory\n");
                return;
        }
        memcpy(&work->data, p, sizeof(work->data));
@@ -1974,8 +1974,7 @@ static int iucv_pm_restore(struct device *dev)
        printk(KERN_WARNING "iucv_pm_restore %p\n", iucv_path_table);
 #endif
        if ((iucv_pm_state != IUCV_PM_RESTORING) && iucv_path_table)
-               pr_warning("Suspending Linux did not completely close all IUCV "
-                       "connections\n");
+               pr_warn("Suspending Linux did not completely close all IUCV connections\n");
        iucv_pm_state = IUCV_PM_RESTORING;
        if (cpumask_empty(&iucv_irq_cpumask)) {
                rc = iucv_query_maxconn();
index 1109d3bb8dac8d4142eb6bdd159915b2f978ea45..2aa2b6c15f2016d81d88976d46056e3a4fd34cb3 100644 (file)
@@ -148,7 +148,7 @@ do {                                                                        \
                 atomic_read(&_t->ref_count));                          \
        l2tp_tunnel_inc_refcount_1(_t);                                 \
 } while (0)
-#define l2tp_tunnel_dec_refcount(_t)
+#define l2tp_tunnel_dec_refcount(_t)                                   \
 do {                                                                   \
        pr_debug("l2tp_tunnel_dec_refcount: %s:%d %s: cnt=%d\n",        \
                 __func__, __LINE__, (_t)->name,                        \
@@ -1392,6 +1392,8 @@ static int l2tp_tunnel_sock_create(struct net *net,
                if (err < 0)
                        goto out;
 
+               udp_set_convert_csum(sock->sk, true);
+
                break;
 
        case L2TP_ENCAPTYPE_IP:
index 13752d96275e8b9142539a201ea1ac6f45f883ba..b704a9356208f5cc3064085b9d82eab52542dd5a 100644 (file)
@@ -755,7 +755,8 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
        /* If PMTU discovery was enabled, use the MTU that was discovered */
        dst = sk_dst_get(tunnel->sock);
        if (dst != NULL) {
-               u32 pmtu = dst_mtu(__sk_dst_get(tunnel->sock));
+               u32 pmtu = dst_mtu(dst);
+
                if (pmtu != 0)
                        session->mtu = session->mru = pmtu -
                                PPPOL2TP_HEADER_OVERHEAD;
index 927b4ea0128bbc365a9692302ba299d5da16b2c4..4d8989b8796067898b3318b08576b32bb6a4d346 100644 (file)
@@ -1011,15 +1011,8 @@ static int sta_apply_parameters(struct ieee80211_local *local,
                        clear_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE);
        }
 
-       if (mask & BIT(NL80211_STA_FLAG_WME)) {
-               if (set & BIT(NL80211_STA_FLAG_WME)) {
-                       set_sta_flag(sta, WLAN_STA_WME);
-                       sta->sta.wme = true;
-               } else {
-                       clear_sta_flag(sta, WLAN_STA_WME);
-                       sta->sta.wme = false;
-               }
-       }
+       if (mask & BIT(NL80211_STA_FLAG_WME))
+               sta->sta.wme = set & BIT(NL80211_STA_FLAG_WME);
 
        if (mask & BIT(NL80211_STA_FLAG_MFP)) {
                if (set & BIT(NL80211_STA_FLAG_MFP))
@@ -3352,7 +3345,7 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
        band = chanctx_conf->def.chan->band;
        sta = sta_info_get_bss(sdata, peer);
        if (sta) {
-               qos = test_sta_flag(sta, WLAN_STA_WME);
+               qos = sta->sta.wme;
        } else {
                rcu_read_unlock();
                return -ENOLINK;
index 6d537f03c0baa0450eefc5c22f496be085072cfd..4c74e8da64b909cc36befe4c5ecb29af5ff7629e 100644 (file)
@@ -541,18 +541,20 @@ static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
                        continue;
                if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf)
                        continue;
+               if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+                       continue;
 
                if (!compat)
                        compat = &sdata->vif.bss_conf.chandef;
 
                compat = cfg80211_chandef_compatible(
                                &sdata->vif.bss_conf.chandef, compat);
-               if (!compat)
+               if (WARN_ON_ONCE(!compat))
                        break;
        }
        rcu_read_unlock();
 
-       if (WARN_ON_ONCE(!compat))
+       if (!compat)
                return;
 
        ieee80211_change_chanctx(local, ctx, compat);
@@ -637,41 +639,6 @@ out:
        return ret;
 }
 
-static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
-{
-       struct ieee80211_local *local = sdata->local;
-       struct ieee80211_chanctx_conf *conf;
-       struct ieee80211_chanctx *ctx;
-       bool use_reserved_switch = false;
-
-       lockdep_assert_held(&local->chanctx_mtx);
-
-       conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
-                                        lockdep_is_held(&local->chanctx_mtx));
-       if (!conf)
-               return;
-
-       ctx = container_of(conf, struct ieee80211_chanctx, conf);
-
-       if (sdata->reserved_chanctx) {
-               if (sdata->reserved_chanctx->replace_state ==
-                   IEEE80211_CHANCTX_REPLACES_OTHER &&
-                   ieee80211_chanctx_num_reserved(local,
-                                                  sdata->reserved_chanctx) > 1)
-                       use_reserved_switch = true;
-
-               ieee80211_vif_unreserve_chanctx(sdata);
-       }
-
-       ieee80211_assign_vif_chanctx(sdata, NULL);
-       if (ieee80211_chanctx_refcount(local, ctx) == 0)
-               ieee80211_free_chanctx(local, ctx);
-
-       /* Unreserving may ready an in-place reservation. */
-       if (use_reserved_switch)
-               ieee80211_vif_use_reserved_switch(local);
-}
-
 void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
                                   struct ieee80211_chanctx *chanctx)
 {
@@ -762,63 +729,6 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
        drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RX_CHAINS);
 }
 
-int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
-                             const struct cfg80211_chan_def *chandef,
-                             enum ieee80211_chanctx_mode mode)
-{
-       struct ieee80211_local *local = sdata->local;
-       struct ieee80211_chanctx *ctx;
-       u8 radar_detect_width = 0;
-       int ret;
-
-       lockdep_assert_held(&local->mtx);
-
-       WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
-
-       mutex_lock(&local->chanctx_mtx);
-
-       ret = cfg80211_chandef_dfs_required(local->hw.wiphy,
-                                           chandef,
-                                           sdata->wdev.iftype);
-       if (ret < 0)
-               goto out;
-       if (ret > 0)
-               radar_detect_width = BIT(chandef->width);
-
-       sdata->radar_required = ret;
-
-       ret = ieee80211_check_combinations(sdata, chandef, mode,
-                                          radar_detect_width);
-       if (ret < 0)
-               goto out;
-
-       __ieee80211_vif_release_channel(sdata);
-
-       ctx = ieee80211_find_chanctx(local, chandef, mode);
-       if (!ctx)
-               ctx = ieee80211_new_chanctx(local, chandef, mode);
-       if (IS_ERR(ctx)) {
-               ret = PTR_ERR(ctx);
-               goto out;
-       }
-
-       sdata->vif.bss_conf.chandef = *chandef;
-
-       ret = ieee80211_assign_vif_chanctx(sdata, ctx);
-       if (ret) {
-               /* if assign fails refcount stays the same */
-               if (ieee80211_chanctx_refcount(local, ctx) == 0)
-                       ieee80211_free_chanctx(local, ctx);
-               goto out;
-       }
-
-       ieee80211_recalc_smps_chanctx(local, ctx);
-       ieee80211_recalc_radar_chanctx(local, ctx);
- out:
-       mutex_unlock(&local->chanctx_mtx);
-       return ret;
-}
-
 static void
 __ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
                                      bool clear)
@@ -1267,8 +1177,7 @@ err:
        return err;
 }
 
-int
-ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
+static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
 {
        struct ieee80211_sub_if_data *sdata, *sdata_tmp;
        struct ieee80211_chanctx *ctx, *ctx_tmp, *old_ctx;
@@ -1444,7 +1353,7 @@ ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
 
                        list_del(&sdata->reserved_chanctx_list);
                        list_move(&sdata->assigned_chanctx_list,
-                                 &new_ctx->assigned_vifs);
+                                 &ctx->assigned_vifs);
                        sdata->reserved_chanctx = NULL;
 
                        ieee80211_vif_chanctx_reservation_complete(sdata);
@@ -1520,6 +1429,98 @@ err:
        return err;
 }
 
+static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_chanctx_conf *conf;
+       struct ieee80211_chanctx *ctx;
+       bool use_reserved_switch = false;
+
+       lockdep_assert_held(&local->chanctx_mtx);
+
+       conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+                                        lockdep_is_held(&local->chanctx_mtx));
+       if (!conf)
+               return;
+
+       ctx = container_of(conf, struct ieee80211_chanctx, conf);
+
+       if (sdata->reserved_chanctx) {
+               if (sdata->reserved_chanctx->replace_state ==
+                   IEEE80211_CHANCTX_REPLACES_OTHER &&
+                   ieee80211_chanctx_num_reserved(local,
+                                                  sdata->reserved_chanctx) > 1)
+                       use_reserved_switch = true;
+
+               ieee80211_vif_unreserve_chanctx(sdata);
+       }
+
+       ieee80211_assign_vif_chanctx(sdata, NULL);
+       if (ieee80211_chanctx_refcount(local, ctx) == 0)
+               ieee80211_free_chanctx(local, ctx);
+
+       /* Unreserving may ready an in-place reservation. */
+       if (use_reserved_switch)
+               ieee80211_vif_use_reserved_switch(local);
+}
+
+int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
+                             const struct cfg80211_chan_def *chandef,
+                             enum ieee80211_chanctx_mode mode)
+{
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_chanctx *ctx;
+       u8 radar_detect_width = 0;
+       int ret;
+
+       lockdep_assert_held(&local->mtx);
+
+       WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
+
+       mutex_lock(&local->chanctx_mtx);
+
+       ret = cfg80211_chandef_dfs_required(local->hw.wiphy,
+                                           chandef,
+                                           sdata->wdev.iftype);
+       if (ret < 0)
+               goto out;
+       if (ret > 0)
+               radar_detect_width = BIT(chandef->width);
+
+       sdata->radar_required = ret;
+
+       ret = ieee80211_check_combinations(sdata, chandef, mode,
+                                          radar_detect_width);
+       if (ret < 0)
+               goto out;
+
+       __ieee80211_vif_release_channel(sdata);
+
+       ctx = ieee80211_find_chanctx(local, chandef, mode);
+       if (!ctx)
+               ctx = ieee80211_new_chanctx(local, chandef, mode);
+       if (IS_ERR(ctx)) {
+               ret = PTR_ERR(ctx);
+               goto out;
+       }
+
+       sdata->vif.bss_conf.chandef = *chandef;
+
+       ret = ieee80211_assign_vif_chanctx(sdata, ctx);
+       if (ret) {
+               /* if assign fails refcount stays the same */
+               if (ieee80211_chanctx_refcount(local, ctx) == 0)
+                       ieee80211_free_chanctx(local, ctx);
+               goto out;
+       }
+
+       ieee80211_recalc_smps_chanctx(local, ctx);
+       ieee80211_recalc_radar_chanctx(local, ctx);
+ out:
+       mutex_unlock(&local->chanctx_mtx);
+       return ret;
+}
+
 int ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_local *local = sdata->local;
index 3db96648b45a02c0e0235b724210a15ba32747b7..33eb4a43a2f342d7c8af78908498020da753b6e2 100644 (file)
@@ -77,7 +77,8 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
                            TEST(AUTH), TEST(ASSOC), TEST(PS_STA),
                            TEST(PS_DRIVER), TEST(AUTHORIZED),
                            TEST(SHORT_PREAMBLE),
-                           TEST(WME), TEST(WDS), TEST(CLEAR_PS_FILT),
+                           sta->sta.wme ? "WME\n" : "",
+                           TEST(WDS), TEST(CLEAR_PS_FILT),
                            TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL),
                            TEST(UAPSD), TEST(SP), TEST(TDLS_PEER),
                            TEST(TDLS_PEER_AUTH), TEST(4ADDR_EVENT),
@@ -167,7 +168,7 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
        p += scnprintf(p, sizeof(buf) + buf - p, "next dialog_token: %#02x\n",
                        sta->ampdu_mlme.dialog_token_allocator + 1);
        p += scnprintf(p, sizeof(buf) + buf - p,
-                      "TID\t\tRX active\tDTKN\tSSN\t\tTX\tDTKN\tpending\n");
+                      "TID\t\tRX\tDTKN\tSSN\t\tTX\tDTKN\tpending\n");
 
        for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
                tid_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[i]);
index 9713dc54ea4bb385abf1d48ae891ff5fceb7440f..5f9654d31a8d3c302e6a9508f693be0a5efb41bc 100644 (file)
@@ -1038,7 +1038,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
                }
 
                if (sta && elems->wmm_info)
-                       set_sta_flag(sta, WLAN_STA_WME);
+                       sta->sta.wme = true;
 
                if (sta && elems->ht_operation && elems->ht_cap_elem &&
                    sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT &&
index ef7a089ac54647eb763b8bbb0793bef98454b48d..ffb20e5e6cf3f5fe51e45f4236ea4bf35151e460 100644 (file)
@@ -1869,7 +1869,6 @@ ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
 int __must_check
 ieee80211_vif_use_reserved_context(struct ieee80211_sub_if_data *sdata);
 int ieee80211_vif_unreserve_chanctx(struct ieee80211_sub_if_data *sdata);
-int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local);
 
 int __must_check
 ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
index 01eede7406a55610e771c7cd906cbedcfff1fa6a..f75e5f132c5ad4a816fc933defedda38f0695e66 100644 (file)
@@ -1175,8 +1175,8 @@ static void ieee80211_iface_work(struct work_struct *work)
                        if (sta) {
                                u16 last_seq;
 
-                               last_seq = le16_to_cpu(
-                                       sta->last_seq_ctrl[rx_agg->tid]);
+                               last_seq = IEEE80211_SEQ_TO_SN(le16_to_cpu(
+                                       sta->last_seq_ctrl[rx_agg->tid]));
 
                                __ieee80211_start_rx_ba_session(sta,
                                                0, 0,
index d808cff8015374ddfb927d5695a3d3973bcc0428..6429d0e1d4a1461dd8ca1ea14498f36e3f087301 100644 (file)
@@ -130,9 +130,7 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
        if (!ret) {
                key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
 
-               if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
-                     (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) ||
-                     (key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)))
+               if (!(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC))
                        sdata->crypto_tx_tailroom_needed_cnt--;
 
                WARN_ON((key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) &&
@@ -180,9 +178,7 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
        sta = key->sta;
        sdata = key->sdata;
 
-       if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
-             (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) ||
-             (key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)))
+       if (!(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC))
                increment_tailroom_need_count(sdata);
 
        ret = drv_set_key(key->local, DISABLE_KEY, sdata,
@@ -878,9 +874,7 @@ void ieee80211_remove_key(struct ieee80211_key_conf *keyconf)
        if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
                key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
 
-               if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
-                     (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) ||
-                     (key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)))
+               if (!(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC))
                        increment_tailroom_need_count(key->sdata);
        }
 
index cf032a8db9d78e9c13fe9df1ee2f2c35dbe8ec62..a6699dceae7c8aeeff4419d8cc2815f9d86adf5e 100644 (file)
@@ -729,7 +729,7 @@ void mesh_plink_broken(struct sta_info *sta)
        tbl = rcu_dereference(mesh_paths);
        for_each_mesh_entry(tbl, node, i) {
                mpath = node->mpath;
-               if (rcu_dereference(mpath->next_hop) == sta &&
+               if (rcu_access_pointer(mpath->next_hop) == sta &&
                    mpath->flags & MESH_PATH_ACTIVE &&
                    !(mpath->flags & MESH_PATH_FIXED)) {
                        spin_lock_bh(&mpath->state_lock);
@@ -794,7 +794,7 @@ void mesh_path_flush_by_nexthop(struct sta_info *sta)
        tbl = resize_dereference_mesh_paths();
        for_each_mesh_entry(tbl, node, i) {
                mpath = node->mpath;
-               if (rcu_dereference(mpath->next_hop) == sta) {
+               if (rcu_access_pointer(mpath->next_hop) == sta) {
                        spin_lock(&tbl->hashwlock[i]);
                        __mesh_path_del(tbl, node);
                        spin_unlock(&tbl->hashwlock[i]);
index 63b874101b2763d5997dc561073e96807596c11a..b488e1859b18e8ed7797cffbb5ab2319138fdb28 100644 (file)
@@ -431,14 +431,12 @@ __mesh_sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *hw_addr)
                return NULL;
 
        sta->plink_state = NL80211_PLINK_LISTEN;
+       sta->sta.wme = true;
 
        sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
        sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
        sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED);
 
-       set_sta_flag(sta, WLAN_STA_WME);
-       sta->sta.wme = true;
-
        return sta;
 }
 
@@ -959,7 +957,8 @@ mesh_plink_get_event(struct ieee80211_sub_if_data *sdata,
                if (!matches_local)
                        event = CNF_RJCT;
                if (!mesh_plink_free_count(sdata) ||
-                   (sta->llid != llid || sta->plid != plid))
+                   sta->llid != llid ||
+                   (sta->plid && sta->plid != plid))
                        event = CNF_IGNR;
                else
                        event = CNF_ACPT;
@@ -1003,7 +1002,6 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
        enum ieee80211_self_protected_actioncode ftype;
        u32 changed = 0;
        u8 ie_len = elems->peering_len;
-       __le16 _plid, _llid;
        u16 plid, llid = 0;
 
        if (!elems->peering) {
@@ -1038,13 +1036,10 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
        /* Note the lines below are correct, the llid in the frame is the plid
         * from the point of view of this host.
         */
-       memcpy(&_plid, PLINK_GET_LLID(elems->peering), sizeof(__le16));
-       plid = le16_to_cpu(_plid);
+       plid = get_unaligned_le16(PLINK_GET_LLID(elems->peering));
        if (ftype == WLAN_SP_MESH_PEERING_CONFIRM ||
-           (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8)) {
-               memcpy(&_llid, PLINK_GET_PLID(elems->peering), sizeof(__le16));
-               llid = le16_to_cpu(_llid);
-       }
+           (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8))
+               llid = get_unaligned_le16(PLINK_GET_PLID(elems->peering));
 
        /* WARNING: Only for sta pointer, is dropped & re-acquired */
        rcu_read_lock();
@@ -1080,6 +1075,10 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
                goto unlock_rcu;
        }
 
+       /* 802.11-2012 13.3.7.2 - update plid on CNF if not set */
+       if (!sta->plid && event == CNF_ACPT)
+               sta->plid = plid;
+
        changed |= mesh_plink_fsm(sdata, sta, event);
 
 unlock_rcu:
index 31a8afaf73323bc09fb99f8e960b17c3fa2e31fd..8a73de6a5f5b46a5659a81159f6a7e78de376dc2 100644 (file)
@@ -149,6 +149,7 @@ static u32
 ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
                             struct ieee80211_supported_band *sband,
                             struct ieee80211_channel *channel,
+                            const struct ieee80211_ht_cap *ht_cap,
                             const struct ieee80211_ht_operation *ht_oper,
                             const struct ieee80211_vht_operation *vht_oper,
                             struct cfg80211_chan_def *chandef, bool tracking)
@@ -162,13 +163,19 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
        chandef->center_freq1 = channel->center_freq;
        chandef->center_freq2 = 0;
 
-       if (!ht_oper || !sband->ht_cap.ht_supported) {
+       if (!ht_cap || !ht_oper || !sband->ht_cap.ht_supported) {
                ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
                goto out;
        }
 
        chandef->width = NL80211_CHAN_WIDTH_20;
 
+       if (!(ht_cap->cap_info &
+             cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH_20_40))) {
+               ret = IEEE80211_STA_DISABLE_40MHZ | IEEE80211_STA_DISABLE_VHT;
+               goto out;
+       }
+
        ht_cfreq = ieee80211_channel_to_frequency(ht_oper->primary_chan,
                                                  channel->band);
        /* check that channel matches the right operating channel */
@@ -328,6 +335,7 @@ out:
 
 static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
                               struct sta_info *sta,
+                              const struct ieee80211_ht_cap *ht_cap,
                               const struct ieee80211_ht_operation *ht_oper,
                               const struct ieee80211_vht_operation *vht_oper,
                               const u8 *bssid, u32 *changed)
@@ -367,8 +375,9 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
        sband = local->hw.wiphy->bands[chan->band];
 
        /* calculate new channel (type) based on HT/VHT operation IEs */
-       flags = ieee80211_determine_chantype(sdata, sband, chan, ht_oper,
-                                            vht_oper, &chandef, true);
+       flags = ieee80211_determine_chantype(sdata, sband, chan,
+                                            ht_cap, ht_oper, vht_oper,
+                                            &chandef, true);
 
        /*
         * Downgrade the new channel if we associated with restricted
@@ -2677,8 +2686,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
        if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED)
                set_sta_flag(sta, WLAN_STA_MFP);
 
-       if (elems.wmm_param)
-               set_sta_flag(sta, WLAN_STA_WME);
+       sta->sta.wme = elems.wmm_param;
 
        err = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
        if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))
@@ -3174,7 +3182,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
        mutex_lock(&local->sta_mtx);
        sta = sta_info_get(sdata, bssid);
 
-       if (ieee80211_config_bw(sdata, sta, elems.ht_operation,
+       if (ieee80211_config_bw(sdata, sta,
+                               elems.ht_cap_elem, elems.ht_operation,
                                elems.vht_operation, bssid, &changed)) {
                mutex_unlock(&local->sta_mtx);
                ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
@@ -3808,6 +3817,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+       const struct ieee80211_ht_cap *ht_cap = NULL;
        const struct ieee80211_ht_operation *ht_oper = NULL;
        const struct ieee80211_vht_operation *vht_oper = NULL;
        struct ieee80211_supported_band *sband;
@@ -3824,14 +3834,17 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
 
        if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) &&
            sband->ht_cap.ht_supported) {
-               const u8 *ht_oper_ie, *ht_cap;
+               const u8 *ht_oper_ie, *ht_cap_ie;
 
                ht_oper_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_OPERATION);
                if (ht_oper_ie && ht_oper_ie[1] >= sizeof(*ht_oper))
                        ht_oper = (void *)(ht_oper_ie + 2);
 
-               ht_cap = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_CAPABILITY);
-               if (!ht_cap || ht_cap[1] < sizeof(struct ieee80211_ht_cap)) {
+               ht_cap_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_CAPABILITY);
+               if (ht_cap_ie && ht_cap_ie[1] >= sizeof(*ht_cap))
+                       ht_cap = (void *)(ht_cap_ie + 2);
+
+               if (!ht_cap) {
                        ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
                        ht_oper = NULL;
                }
@@ -3862,7 +3875,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
 
        ifmgd->flags |= ieee80211_determine_chantype(sdata, sband,
                                                     cbss->channel,
-                                                    ht_oper, vht_oper,
+                                                    ht_cap, ht_oper, vht_oper,
                                                     &chandef, false);
 
        sdata->needed_rx_chains = min(ieee80211_ht_vht_rx_chains(sdata, cbss),
@@ -4376,8 +4389,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
        rcu_read_unlock();
 
        if (bss->wmm_used && bss->uapsd_supported &&
-           (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD) &&
-           sdata->wmm_acm != 0xff) {
+           (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) {
                assoc_data->uapsd = true;
                ifmgd->flags |= IEEE80211_STA_UAPSD_ENABLED;
        } else {
index bd2c9b22c945669f8ec1d48e3959101fd9ce6754..a8d862f9183c9785158465748e344ce9113aba00 100644 (file)
@@ -2725,7 +2725,7 @@ ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx)
                sig = status->signal;
 
        if (cfg80211_rx_mgmt(&rx->sdata->wdev, status->freq, sig,
-                            rx->skb->data, rx->skb->len, 0, GFP_ATOMIC)) {
+                            rx->skb->data, rx->skb->len, 0)) {
                if (rx->sta)
                        rx->sta->rx_packets++;
                dev_kfree_skb(rx->skb);
index a0a938145dcc87397cb4ecfad5f59b1c5fb28dbc..a9bb6eb8c3e0f8c3f3b8e623a91817f2579e74fe 100644 (file)
@@ -1094,7 +1094,7 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata)
        if (rcu_access_pointer(local->sched_scan_sdata)) {
                ret = drv_sched_scan_stop(local, sdata);
                if (!ret)
-                       rcu_assign_pointer(local->sched_scan_sdata, NULL);
+                       RCU_INIT_POINTER(local->sched_scan_sdata, NULL);
        }
 out:
        mutex_unlock(&local->mtx);
index c6ee2139fbc579bab35e8cc5bfb6f3b4994930d2..7300305420244a6825ead12e641145c984e5530c 100644 (file)
@@ -1094,8 +1094,11 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
        unsigned long flags;
        struct ps_data *ps;
 
-       if (sdata->vif.type == NL80211_IFTYPE_AP ||
-           sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+       if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+               sdata = container_of(sdata->bss, struct ieee80211_sub_if_data,
+                                    u.ap);
+
+       if (sdata->vif.type == NL80211_IFTYPE_AP)
                ps = &sdata->bss->ps;
        else if (ieee80211_vif_is_mesh(&sdata->vif))
                ps = &sdata->u.mesh.ps;
@@ -1179,7 +1182,7 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata,
        struct sk_buff *skb;
        int size = sizeof(*nullfunc);
        __le16 fc;
-       bool qos = test_sta_flag(sta, WLAN_STA_WME);
+       bool qos = sta->sta.wme;
        struct ieee80211_tx_info *info;
        struct ieee80211_chanctx_conf *chanctx_conf;
 
@@ -1834,7 +1837,7 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
                sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHORIZED);
        if (test_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE))
                sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);
-       if (test_sta_flag(sta, WLAN_STA_WME))
+       if (sta->sta.wme)
                sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_WME);
        if (test_sta_flag(sta, WLAN_STA_MFP))
                sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_MFP);
index d411bcc8ef085215b8369fc0f066a49fd65fc6eb..89c40d5c0633921649982787d8f6fc3756261eaa 100644 (file)
@@ -31,7 +31,6 @@
  *     when virtual port control is not in use.
  * @WLAN_STA_SHORT_PREAMBLE: Station is capable of receiving short-preamble
  *     frames.
- * @WLAN_STA_WME: Station is a QoS-STA.
  * @WLAN_STA_WDS: Station is one of our WDS peers.
  * @WLAN_STA_CLEAR_PS_FILT: Clear PS filter in hardware (using the
  *     IEEE80211_TX_CTL_CLEAR_PS_FILT control flag) when the next
@@ -69,7 +68,6 @@ enum ieee80211_sta_info_flags {
        WLAN_STA_PS_STA,
        WLAN_STA_AUTHORIZED,
        WLAN_STA_SHORT_PREAMBLE,
-       WLAN_STA_WME,
        WLAN_STA_WDS,
        WLAN_STA_CLEAR_PS_FILT,
        WLAN_STA_MFP,
index 1b21050be174b29539a954991d0376dab76fc78f..f2cb3b6c1871e6b67f418b04f091af5609b117a8 100644 (file)
@@ -316,8 +316,7 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata,
        }
 
        /* add the QoS param IE if both the peer and we support it */
-       if (local->hw.queues >= IEEE80211_NUM_ACS &&
-           test_sta_flag(sta, WLAN_STA_WME))
+       if (local->hw.queues >= IEEE80211_NUM_ACS && sta->sta.wme)
                ieee80211_tdls_add_wmm_param_ie(sdata, skb);
 
        /* add any custom IEs that go before HT operation */
index 464106c023d8c7d9cb1bd65b39ad642bd1090bc1..925c39f4099eadfa4744263d1485fe0611a16e69 100644 (file)
@@ -1478,7 +1478,10 @@ static int ieee80211_skb_resize(struct ieee80211_sub_if_data *sdata,
                tail_need = max_t(int, tail_need, 0);
        }
 
-       if (skb_cloned(skb))
+       if (skb_cloned(skb) &&
+           (!(local->hw.flags & IEEE80211_HW_SUPPORTS_CLONED_SKBS) ||
+            !skb_clone_writable(skb, ETH_HLEN) ||
+            sdata->crypto_tx_tailroom_needed_cnt))
                I802_DEBUG_INC(local->tx_expand_skb_head_cloned);
        else if (head_need || tail_need)
                I802_DEBUG_INC(local->tx_expand_skb_head);
@@ -1844,7 +1847,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                        memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
                        hdrlen = 30;
                        authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
-                       wme_sta = test_sta_flag(sta, WLAN_STA_WME);
+                       wme_sta = sta->sta.wme;
                }
                ap_sdata = container_of(sdata->bss, struct ieee80211_sub_if_data,
                                        u.ap);
@@ -1957,7 +1960,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                        if (sta) {
                                authorized = test_sta_flag(sta,
                                                        WLAN_STA_AUTHORIZED);
-                               wme_sta = test_sta_flag(sta, WLAN_STA_WME);
+                               wme_sta = sta->sta.wme;
                                tdls_peer = test_sta_flag(sta,
                                                          WLAN_STA_TDLS_PEER);
                                tdls_auth = test_sta_flag(sta,
@@ -2035,7 +2038,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                sta = sta_info_get(sdata, hdr.addr1);
                if (sta) {
                        authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
-                       wme_sta = test_sta_flag(sta, WLAN_STA_WME);
+                       wme_sta = sta->sta.wme;
                }
        }
 
index d51422c778dee359bec450c75b77bfb24ca712f4..6459946f0b741cbfd05dca843ae06380435601d6 100644 (file)
@@ -118,7 +118,7 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
        case NL80211_IFTYPE_AP_VLAN:
                sta = rcu_dereference(sdata->u.vlan.sta);
                if (sta) {
-                       qos = test_sta_flag(sta, WLAN_STA_WME);
+                       qos = sta->sta.wme;
                        break;
                }
        case NL80211_IFTYPE_AP:
@@ -145,7 +145,7 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
        if (!sta && ra && !is_multicast_ether_addr(ra)) {
                sta = sta_info_get(sdata, ra);
                if (sta)
-                       qos = test_sta_flag(sta, WLAN_STA_WME);
+                       qos = sta->sta.wme;
        }
        rcu_read_unlock();
 
index 7f820a108a9cf3461a46a57522251ea4edc51003..a14cf9ede171e7bcc2c1373931e5e7754b36bab4 100644 (file)
@@ -86,9 +86,8 @@ fail:
 static void mac802154_rx_worker(struct work_struct *work)
 {
        struct rx_work *rw = container_of(work, struct rx_work, work);
-       struct sk_buff *skb = rw->skb;
 
-       mac802154_subif_rx(rw->dev, skb, rw->lqi);
+       mac802154_subif_rx(rw->dev, rw->skb, rw->lqi);
        kfree(rw);
 }
 
@@ -101,7 +100,7 @@ ieee802154_rx_irqsafe(struct ieee802154_dev *dev, struct sk_buff *skb, u8 lqi)
        if (!skb)
                return;
 
-       work = kzalloc(sizeof(struct rx_work), GFP_ATOMIC);
+       work = kzalloc(sizeof(*work), GFP_ATOMIC);
        if (!work)
                return;
 
index 8124353646ae64239556a0ed915f046f7e689864..fdf4c0e67259ecceacc0b06b9060405ded6f63cc 100644 (file)
@@ -89,8 +89,7 @@ netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb,
 
        if (!(priv->phy->channels_supported[page] & (1 << chan))) {
                WARN_ON(1);
-               kfree_skb(skb);
-               return NETDEV_TX_OK;
+               goto err_tx;
        }
 
        mac802154_monitors_rx(mac802154_to_priv(&priv->hw), skb);
@@ -103,12 +102,10 @@ netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb,
                data[1] = crc >> 8;
        }
 
-       if (skb_cow_head(skb, priv->hw.extra_tx_headroom)) {
-               kfree_skb(skb);
-               return NETDEV_TX_OK;
-       }
+       if (skb_cow_head(skb, priv->hw.extra_tx_headroom))
+               goto err_tx;
 
-       work = kzalloc(sizeof(struct xmit_work), GFP_ATOMIC);
+       work = kzalloc(sizeof(*work), GFP_ATOMIC);
        if (!work) {
                kfree_skb(skb);
                return NETDEV_TX_BUSY;
@@ -129,4 +126,8 @@ netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb,
        queue_work(priv->dev_workqueue, &work->work);
 
        return NETDEV_TX_OK;
+
+err_tx:
+       kfree_skb(skb);
+       return NETDEV_TX_OK;
 }
index 3c3069fd69718277fc719e82d7bf2c51bb9747db..b7961129ce4d28f838362120c97c511770c981e5 100644 (file)
@@ -462,7 +462,10 @@ mac802154_subif_frame(struct mac802154_sub_if_data *sdata, struct sk_buff *skb,
                        skb->pkt_type = PACKET_OTHERHOST;
                break;
        default:
-               break;
+               spin_unlock_bh(&sdata->mib_lock);
+               pr_debug("invalid dest mode\n");
+               kfree_skb(skb);
+               return NET_RX_DROP;
        }
 
        spin_unlock_bh(&sdata->mib_lock);
@@ -472,8 +475,7 @@ mac802154_subif_frame(struct mac802154_sub_if_data *sdata, struct sk_buff *skb,
        rc = mac802154_llsec_decrypt(&sdata->sec, skb);
        if (rc) {
                pr_debug("decryption failed: %i\n", rc);
-               kfree_skb(skb);
-               return NET_RX_DROP;
+               goto fail;
        }
 
        sdata->dev->stats.rx_packets++;
@@ -485,9 +487,12 @@ mac802154_subif_frame(struct mac802154_sub_if_data *sdata, struct sk_buff *skb,
        default:
                pr_warn("ieee802154: bad frame received (type = %d)\n",
                        mac_cb(skb)->type);
-               kfree_skb(skb);
-               return NET_RX_DROP;
+               goto fail;
        }
+
+fail:
+       kfree_skb(skb);
+       return NET_RX_DROP;
 }
 
 static void mac802154_print_addr(const char *name,
@@ -573,6 +578,7 @@ void mac802154_wpans_rx(struct mac802154_priv *priv, struct sk_buff *skb)
        ret = mac802154_parse_frame_start(skb, &hdr);
        if (ret) {
                pr_debug("got invalid frame\n");
+               kfree_skb(skb);
                return;
        }
 
index 37428723394f65287b2668f03d7c5a3aa13023f2..608d189869236c8f22aeeb229c246de478a157d9 100644 (file)
@@ -508,7 +508,7 @@ config NFT_MASQ
 config NFT_NAT
        depends on NF_TABLES
        depends on NF_CONNTRACK
-       depends on NF_NAT
+       select NF_NAT
        tristate "Netfilter nf_tables nat module"
        help
          This option adds the "nat" expression that you can use to perform
@@ -756,7 +756,9 @@ config NETFILTER_XT_TARGET_LED
 
 config NETFILTER_XT_TARGET_LOG
        tristate "LOG target support"
-       depends on NF_LOG_IPV4 && NF_LOG_IPV6
+       select NF_LOG_COMMON
+       select NF_LOG_IPV4
+       select NF_LOG_IPV6 if IPV6
        default m if NETFILTER_ADVANCED=n
        help
          This option adds a `LOG' target, which allows you to create rules in
@@ -773,6 +775,14 @@ config NETFILTER_XT_TARGET_MARK
        (e.g. when running oldconfig). It selects
        CONFIG_NETFILTER_XT_MARK (combined mark/MARK module).
 
+config NETFILTER_XT_NAT
+       tristate '"SNAT and DNAT" targets support'
+       depends on NF_NAT
+       ---help---
+       This option enables the SNAT and DNAT targets.
+
+       To compile it as a module, choose M here. If unsure, say N.
+
 config NETFILTER_XT_TARGET_NETMAP
        tristate '"NETMAP" target support'
        depends on NF_NAT
index 0637792f6faf5622e988d53f8b167d3e86c45715..a9571be3f7914cff0619cb5c7d5829f56feab35f 100644 (file)
@@ -96,7 +96,7 @@ obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o
 obj-$(CONFIG_NETFILTER_XT_MARK) += xt_mark.o
 obj-$(CONFIG_NETFILTER_XT_CONNMARK) += xt_connmark.o
 obj-$(CONFIG_NETFILTER_XT_SET) += xt_set.o
-obj-$(CONFIG_NF_NAT) += xt_nat.o
+obj-$(CONFIG_NETFILTER_XT_NAT) += xt_nat.o
 
 # targets
 obj-$(CONFIG_NETFILTER_XT_TARGET_AUDIT) += xt_AUDIT.o
index a93c97f106d4a5022cd0e1196ee70ecdfd8c2873..024a2e25c8a49448afbeed4f780912b24a6318a3 100644 (file)
@@ -54,7 +54,7 @@ EXPORT_SYMBOL_GPL(nf_unregister_afinfo);
 struct list_head nf_hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS] __read_mostly;
 EXPORT_SYMBOL(nf_hooks);
 
-#if defined(CONFIG_JUMP_LABEL)
+#ifdef HAVE_JUMP_LABEL
 struct static_key nf_hooks_needed[NFPROTO_NUMPROTO][NF_MAX_HOOKS];
 EXPORT_SYMBOL(nf_hooks_needed);
 #endif
@@ -72,7 +72,7 @@ int nf_register_hook(struct nf_hook_ops *reg)
        }
        list_add_rcu(&reg->list, elem->list.prev);
        mutex_unlock(&nf_hook_mutex);
-#if defined(CONFIG_JUMP_LABEL)
+#ifdef HAVE_JUMP_LABEL
        static_key_slow_inc(&nf_hooks_needed[reg->pf][reg->hooknum]);
 #endif
        return 0;
@@ -84,7 +84,7 @@ void nf_unregister_hook(struct nf_hook_ops *reg)
        mutex_lock(&nf_hook_mutex);
        list_del_rcu(&reg->list);
        mutex_unlock(&nf_hook_mutex);
-#if defined(CONFIG_JUMP_LABEL)
+#ifdef HAVE_JUMP_LABEL
        static_key_slow_dec(&nf_hooks_needed[reg->pf][reg->hooknum]);
 #endif
        synchronize_net();
index ec8114fae50b297f56760c3ac22d378c31957cd4..5593e97426c45cfa47559b5b631f42211ef13cda 100644 (file)
@@ -101,7 +101,7 @@ load_settype(const char *name)
        nfnl_unlock(NFNL_SUBSYS_IPSET);
        pr_debug("try to load ip_set_%s\n", name);
        if (request_module("ip_set_%s", name) < 0) {
-               pr_warning("Can't find ip_set type %s\n", name);
+               pr_warn("Can't find ip_set type %s\n", name);
                nfnl_lock(NFNL_SUBSYS_IPSET);
                return false;
        }
@@ -195,20 +195,19 @@ ip_set_type_register(struct ip_set_type *type)
        int ret = 0;
 
        if (type->protocol != IPSET_PROTOCOL) {
-               pr_warning("ip_set type %s, family %s, revision %u:%u uses "
-                          "wrong protocol version %u (want %u)\n",
-                          type->name, family_name(type->family),
-                          type->revision_min, type->revision_max,
-                          type->protocol, IPSET_PROTOCOL);
+               pr_warn("ip_set type %s, family %s, revision %u:%u uses wrong protocol version %u (want %u)\n",
+                       type->name, family_name(type->family),
+                       type->revision_min, type->revision_max,
+                       type->protocol, IPSET_PROTOCOL);
                return -EINVAL;
        }
 
        ip_set_type_lock();
        if (find_set_type(type->name, type->family, type->revision_min)) {
                /* Duplicate! */
-               pr_warning("ip_set type %s, family %s with revision min %u "
-                          "already registered!\n", type->name,
-                          family_name(type->family), type->revision_min);
+               pr_warn("ip_set type %s, family %s with revision min %u already registered!\n",
+                       type->name, family_name(type->family),
+                       type->revision_min);
                ret = -EINVAL;
                goto unlock;
        }
@@ -228,9 +227,9 @@ ip_set_type_unregister(struct ip_set_type *type)
 {
        ip_set_type_lock();
        if (!find_set_type(type->name, type->family, type->revision_min)) {
-               pr_warning("ip_set type %s, family %s with revision min %u "
-                          "not registered\n", type->name,
-                          family_name(type->family), type->revision_min);
+               pr_warn("ip_set type %s, family %s with revision min %u not registered\n",
+                       type->name, family_name(type->family),
+                       type->revision_min);
                goto unlock;
        }
        list_del_rcu(&type->list);
index 0398a92da6cca8bbece002e62293ce718841f161..8a38890cbe5eb283794b29ec629b4d94f919052e 100644 (file)
@@ -565,8 +565,8 @@ retry:
                 set->name, orig->htable_bits, htable_bits, orig);
        if (!htable_bits) {
                /* In case we have plenty of memory :-) */
-               pr_warning("Cannot increase the hashsize of set %s further\n",
-                          set->name);
+               pr_warn("Cannot increase the hashsize of set %s further\n",
+                       set->name);
                return -IPSET_ERR_HASH_FULL;
        }
        t = ip_set_alloc(sizeof(*t)
@@ -651,8 +651,8 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
 
        if (h->elements >= h->maxelem) {
                if (net_ratelimit())
-                       pr_warning("Set %s is full, maxelem %u reached\n",
-                                  set->name, h->maxelem);
+                       pr_warn("Set %s is full, maxelem %u reached\n",
+                               set->name, h->maxelem);
                return -IPSET_ERR_HASH_FULL;
        }
 
@@ -998,8 +998,8 @@ mtype_list(const struct ip_set *set,
 nla_put_failure:
        nlmsg_trim(skb, incomplete);
        if (unlikely(first == cb->args[IPSET_CB_ARG0])) {
-               pr_warning("Can't list set %s: one bucket does not fit into "
-                          "a message. Please report it!\n", set->name);
+               pr_warn("Can't list set %s: one bucket does not fit into a message. Please report it!\n",
+                       set->name);
                cb->args[IPSET_CB_ARG0] = 0;
                return -EMSGSIZE;
        }
index e6836755c45d4168bb6ccc9ab6f12708e9e17f3d..5c34e8d42e0190a14ec31c1238bde5929fdf0539 100644 (file)
@@ -1906,7 +1906,7 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
        {
                .hook           = ip_vs_local_reply6,
                .owner          = THIS_MODULE,
-               .pf             = NFPROTO_IPV4,
+               .pf             = NFPROTO_IPV6,
                .hooknum        = NF_INET_LOCAL_OUT,
                .priority       = NF_IP6_PRI_NAT_DST + 1,
        },
index 6f70bdd3a90ad85c72cb100de997d2f5b5bc40a1..56896a412bcec7ae01726734115d19bc04079274 100644 (file)
@@ -38,6 +38,7 @@
 #include <net/route.h>                  /* for ip_route_output */
 #include <net/ipv6.h>
 #include <net/ip6_route.h>
+#include <net/ip_tunnels.h>
 #include <net/addrconf.h>
 #include <linux/icmpv6.h>
 #include <linux/netfilter.h>
@@ -862,11 +863,15 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
                old_iph = ip_hdr(skb);
        }
 
-       skb->transport_header = skb->network_header;
-
        /* fix old IP header checksum */
        ip_send_check(old_iph);
 
+       skb = iptunnel_handle_offloads(skb, false, SKB_GSO_IPIP);
+       if (IS_ERR(skb))
+               goto tx_error;
+
+       skb->transport_header = skb->network_header;
+
        skb_push(skb, sizeof(struct iphdr));
        skb_reset_network_header(skb);
        memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
@@ -900,7 +905,8 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
        return NF_STOLEN;
 
   tx_error:
-       kfree_skb(skb);
+       if (!IS_ERR(skb))
+               kfree_skb(skb);
        rcu_read_unlock();
        LeaveFunction(10);
        return NF_STOLEN;
@@ -953,6 +959,11 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
                old_iph = ipv6_hdr(skb);
        }
 
+       /* GSO: we need to provide proper SKB_GSO_ value for IPv6 */
+       skb = iptunnel_handle_offloads(skb, false, 0); /* SKB_GSO_SIT/IPV6 */
+       if (IS_ERR(skb))
+               goto tx_error;
+
        skb->transport_header = skb->network_header;
 
        skb_push(skb, sizeof(struct ipv6hdr));
@@ -988,7 +999,8 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
        return NF_STOLEN;
 
 tx_error:
-       kfree_skb(skb);
+       if (!IS_ERR(skb))
+               kfree_skb(skb);
        rcu_read_unlock();
        LeaveFunction(10);
        return NF_STOLEN;
index de88c4ab5146a168bc0866f3fdc07098b5ebe543..5016a6929085ebdbf151a1f47582d36195885540 100644 (file)
@@ -142,7 +142,7 @@ static u32 hash_conntrack_raw(const struct nf_conntrack_tuple *tuple, u16 zone)
 
 static u32 __hash_bucket(u32 hash, unsigned int size)
 {
-       return ((u64)hash * size) >> 32;
+       return reciprocal_scale(hash, size);
 }
 
 static u32 hash_bucket(u32 hash, const struct net *net)
@@ -358,7 +358,7 @@ bool nf_ct_delete(struct nf_conn *ct, u32 portid, int report)
 
        tstamp = nf_conn_tstamp_find(ct);
        if (tstamp && tstamp->stop == 0)
-               tstamp->stop = ktime_to_ns(ktime_get_real());
+               tstamp->stop = ktime_get_real_ns();
 
        if (nf_ct_is_dying(ct))
                goto delete;
index f87e8f68ad453e9baeec017cc74534e8ce85dfab..91a1837acd0e8fb981ccea73ae262197afecfb33 100644 (file)
@@ -83,7 +83,8 @@ static unsigned int nf_ct_expect_dst_hash(const struct nf_conntrack_tuple *tuple
        hash = jhash2(tuple->dst.u3.all, ARRAY_SIZE(tuple->dst.u3.all),
                      (((tuple->dst.protonum ^ tuple->src.l3num) << 16) |
                       (__force __u16)tuple->dst.u.all) ^ nf_conntrack_hash_rnd);
-       return ((u64)hash * nf_ct_expect_hsize) >> 32;
+
+       return reciprocal_scale(hash, nf_ct_expect_hsize);
 }
 
 struct nf_conntrack_expect *
index 355a5c4ef7635bb7aca1e1068ca269b891949550..1bd9ed9e62f642477e8a10d57cd73775cc1ebc14 100644 (file)
@@ -1737,7 +1737,7 @@ ctnetlink_create_conntrack(struct net *net, u16 zone,
        }
        tstamp = nf_conn_tstamp_find(ct);
        if (tstamp)
-               tstamp->start = ktime_to_ns(ktime_get_real());
+               tstamp->start = ktime_get_real_ns();
 
        err = nf_conntrack_hash_check_insert(ct);
        if (err < 0)
index f641751dba9dc467b4207716bdb0ac69208747f8..cf65a1e040dd8c8920dd8fc330c75c218ea7050b 100644 (file)
@@ -101,7 +101,7 @@ static void *ct_seq_start(struct seq_file *seq, loff_t *pos)
 {
        struct ct_iter_state *st = seq->private;
 
-       st->time_now = ktime_to_ns(ktime_get_real());
+       st->time_now = ktime_get_real_ns();
        rcu_read_lock();
        return ct_get_idx(seq, *pos);
 }
index 552f97cd9fde5c510ac055642affb66adbda181d..4e0b47831d43a25f021a1eeb2c62c2307b8630e1 100644 (file)
@@ -126,7 +126,8 @@ hash_by_src(const struct net *net, u16 zone,
        /* Original src, to ensure we map it consistently if poss. */
        hash = jhash2((u32 *)&tuple->src, sizeof(tuple->src) / sizeof(u32),
                      tuple->dst.protonum ^ zone ^ nf_conntrack_hash_rnd);
-       return ((u64)hash * net->ct.nat_htable_size) >> 32;
+
+       return reciprocal_scale(hash, net->ct.nat_htable_size);
 }
 
 /* Is this tuple already taken? (not by us) */
@@ -274,7 +275,7 @@ find_best_ips_proto(u16 zone, struct nf_conntrack_tuple *tuple,
                }
 
                var_ipp->all[i] = (__force __u32)
-                       htonl(minip + (((u64)j * dist) >> 32));
+                       htonl(minip + reciprocal_scale(j, dist));
                if (var_ipp->all[i] != range->max_addr.all[i])
                        full_range = true;
 
index 73b73f687c580ccfe66648234caab5f0bdc543b9..02afaf48a7290b15e6f2d56b2ca2c5cb07455b4d 100644 (file)
@@ -126,7 +126,7 @@ hmark_hash(struct hmark_tuple *t, const struct xt_hmark_info *info)
        hash = jhash_3words(src, dst, t->uports.v32, info->hashrnd);
        hash = hash ^ (t->proto & info->proto_mask);
 
-       return (((u64)hash * info->hmodulus) >> 32) + info->hoffset;
+       return reciprocal_scale(hash, info->hmodulus) + info->hoffset;
 }
 
 static void
index f4e833005320fa7da4c0deb41bba272e8c54bd8e..7198d660b4dea1e9e79c6f9a13f4e6669bca569d 100644 (file)
@@ -31,7 +31,7 @@ static int cgroup_mt_check(const struct xt_mtchk_param *par)
        if (info->invert & ~1)
                return -EINVAL;
 
-       return info->id ? 0 : -EINVAL;
+       return 0;
 }
 
 static bool
index f4af1bfafb1c61642ddb56ac490f7e161df5d39d..96fa26b20b67dce9ed2d2abaaf6ce71dda363faf 100644 (file)
@@ -55,7 +55,8 @@ xt_cluster_hash(const struct nf_conn *ct,
                WARN_ON(1);
                break;
        }
-       return (((u64)hash * info->total_nodes) >> 32);
+
+       return reciprocal_scale(hash, info->total_nodes);
 }
 
 static inline bool
index 1e634615ab9d6e4b2a5c7db5872332c5a522f435..d4bec261e74e636e5a51c8ea95480f15bc61a1ab 100644 (file)
@@ -120,7 +120,7 @@ static int connbytes_mt_check(const struct xt_mtchk_param *par)
         * accounting is enabled, so complain in the hope that someone notices.
         */
        if (!nf_ct_acct_enabled(par->net)) {
-               pr_warning("Forcing CT accounting to be enabled\n");
+               pr_warn("Forcing CT accounting to be enabled\n");
                nf_ct_set_acct(par->net, true);
        }
 
index 47dc6836830a9cfe1b329fbdddabfd1d80c4d100..05fbc2a0be4614aff1fbe55fccce25eb30041c0e 100644 (file)
@@ -135,7 +135,7 @@ hash_dst(const struct xt_hashlimit_htable *ht, const struct dsthash_dst *dst)
         * give results between [0 and cfg.size-1] and same hash distribution,
         * but using a multiply, less expensive than a divide
         */
-       return ((u64)hash * ht->cfg.size) >> 32;
+       return reciprocal_scale(hash, ht->cfg.size);
 }
 
 static struct dsthash_ent *
@@ -943,7 +943,7 @@ static int __init hashlimit_mt_init(void)
                                            sizeof(struct dsthash_ent), 0, 0,
                                            NULL);
        if (!hashlimit_cachep) {
-               pr_warning("unable to create slab cache\n");
+               pr_warn("unable to create slab cache\n");
                goto err2;
        }
        return 0;
index 80c2e2d603e00c718ad1744804ef29f926b9d404..cb70f6ec5695f8216b303c733a9985ae9c0778e0 100644 (file)
@@ -84,13 +84,12 @@ set_match_v0_checkentry(const struct xt_mtchk_param *par)
        index = ip_set_nfnl_get_byindex(par->net, info->match_set.index);
 
        if (index == IPSET_INVALID_ID) {
-               pr_warning("Cannot find set identified by id %u to match\n",
-                          info->match_set.index);
+               pr_warn("Cannot find set identified by id %u to match\n",
+                       info->match_set.index);
                return -ENOENT;
        }
        if (info->match_set.u.flags[IPSET_DIM_MAX-1] != 0) {
-               pr_warning("Protocol error: set match dimension "
-                          "is over the limit!\n");
+               pr_warn("Protocol error: set match dimension is over the limit!\n");
                ip_set_nfnl_put(par->net, info->match_set.index);
                return -ERANGE;
        }
@@ -134,13 +133,12 @@ set_match_v1_checkentry(const struct xt_mtchk_param *par)
        index = ip_set_nfnl_get_byindex(par->net, info->match_set.index);
 
        if (index == IPSET_INVALID_ID) {
-               pr_warning("Cannot find set identified by id %u to match\n",
-                          info->match_set.index);
+               pr_warn("Cannot find set identified by id %u to match\n",
+                       info->match_set.index);
                return -ENOENT;
        }
        if (info->match_set.dim > IPSET_DIM_MAX) {
-               pr_warning("Protocol error: set match dimension "
-                          "is over the limit!\n");
+               pr_warn("Protocol error: set match dimension is over the limit!\n");
                ip_set_nfnl_put(par->net, info->match_set.index);
                return -ERANGE;
        }
@@ -230,8 +228,8 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par)
        if (info->add_set.index != IPSET_INVALID_ID) {
                index = ip_set_nfnl_get_byindex(par->net, info->add_set.index);
                if (index == IPSET_INVALID_ID) {
-                       pr_warning("Cannot find add_set index %u as target\n",
-                                  info->add_set.index);
+                       pr_warn("Cannot find add_set index %u as target\n",
+                               info->add_set.index);
                        return -ENOENT;
                }
        }
@@ -239,8 +237,8 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par)
        if (info->del_set.index != IPSET_INVALID_ID) {
                index = ip_set_nfnl_get_byindex(par->net, info->del_set.index);
                if (index == IPSET_INVALID_ID) {
-                       pr_warning("Cannot find del_set index %u as target\n",
-                                  info->del_set.index);
+                       pr_warn("Cannot find del_set index %u as target\n",
+                               info->del_set.index);
                        if (info->add_set.index != IPSET_INVALID_ID)
                                ip_set_nfnl_put(par->net, info->add_set.index);
                        return -ENOENT;
@@ -248,8 +246,7 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par)
        }
        if (info->add_set.u.flags[IPSET_DIM_MAX-1] != 0 ||
            info->del_set.u.flags[IPSET_DIM_MAX-1] != 0) {
-               pr_warning("Protocol error: SET target dimension "
-                          "is over the limit!\n");
+               pr_warn("Protocol error: SET target dimension is over the limit!\n");
                if (info->add_set.index != IPSET_INVALID_ID)
                        ip_set_nfnl_put(par->net, info->add_set.index);
                if (info->del_set.index != IPSET_INVALID_ID)
@@ -303,8 +300,8 @@ set_target_v1_checkentry(const struct xt_tgchk_param *par)
        if (info->add_set.index != IPSET_INVALID_ID) {
                index = ip_set_nfnl_get_byindex(par->net, info->add_set.index);
                if (index == IPSET_INVALID_ID) {
-                       pr_warning("Cannot find add_set index %u as target\n",
-                                  info->add_set.index);
+                       pr_warn("Cannot find add_set index %u as target\n",
+                               info->add_set.index);
                        return -ENOENT;
                }
        }
@@ -312,8 +309,8 @@ set_target_v1_checkentry(const struct xt_tgchk_param *par)
        if (info->del_set.index != IPSET_INVALID_ID) {
                index = ip_set_nfnl_get_byindex(par->net, info->del_set.index);
                if (index == IPSET_INVALID_ID) {
-                       pr_warning("Cannot find del_set index %u as target\n",
-                                  info->del_set.index);
+                       pr_warn("Cannot find del_set index %u as target\n",
+                               info->del_set.index);
                        if (info->add_set.index != IPSET_INVALID_ID)
                                ip_set_nfnl_put(par->net, info->add_set.index);
                        return -ENOENT;
@@ -321,8 +318,7 @@ set_target_v1_checkentry(const struct xt_tgchk_param *par)
        }
        if (info->add_set.dim > IPSET_DIM_MAX ||
            info->del_set.dim > IPSET_DIM_MAX) {
-               pr_warning("Protocol error: SET target dimension "
-                          "is over the limit!\n");
+               pr_warn("Protocol error: SET target dimension is over the limit!\n");
                if (info->add_set.index != IPSET_INVALID_ID)
                        ip_set_nfnl_put(par->net, info->add_set.index);
                if (info->del_set.index != IPSET_INVALID_ID)
index fe5cda0deb395db1d6a619e2145c22945ea05d74..5231652a95d90fa2c5d18193380c1a8b6c7dae62 100644 (file)
@@ -42,6 +42,9 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
 
 static int make_writable(struct sk_buff *skb, int write_len)
 {
+       if (!pskb_may_pull(skb, write_len))
+               return -ENOMEM;
+
        if (!skb_cloned(skb) || skb_clone_writable(skb, write_len))
                return 0;
 
@@ -70,6 +73,8 @@ static int __pop_vlan_tci(struct sk_buff *skb, __be16 *current_tci)
 
        vlan_set_encap_proto(skb, vhdr);
        skb->mac_header += VLAN_HLEN;
+       if (skb_network_offset(skb) < ETH_HLEN)
+               skb_set_network_header(skb, ETH_HLEN);
        skb_reset_mac_len(skb);
 
        return 0;
index 7228ec3faf19cdc02a685caa04ccbf04ddf8005a..91d66b7e64ac71f31dcc78208857a20ce7a97f79 100644 (file)
@@ -265,8 +265,11 @@ void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb)
                upcall.key = &key;
                upcall.userdata = NULL;
                upcall.portid = ovs_vport_find_upcall_portid(p, skb);
-               ovs_dp_upcall(dp, skb, &upcall);
-               consume_skb(skb);
+               error = ovs_dp_upcall(dp, skb, &upcall);
+               if (unlikely(error))
+                       kfree_skb(skb);
+               else
+                       consume_skb(skb);
                stats_counter = &stats->n_missed;
                goto out;
        }
@@ -404,7 +407,7 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
 {
        struct ovs_header *upcall;
        struct sk_buff *nskb = NULL;
-       struct sk_buff *user_skb; /* to be queued to userspace */
+       struct sk_buff *user_skb = NULL; /* to be queued to userspace */
        struct nlattr *nla;
        struct genl_info info = {
                .dst_sk = ovs_dp_get_net(dp)->genl_sock,
@@ -494,9 +497,11 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
        ((struct nlmsghdr *) user_skb->data)->nlmsg_len = user_skb->len;
 
        err = genlmsg_unicast(ovs_dp_get_net(dp), user_skb, upcall_info->portid);
+       user_skb = NULL;
 out:
        if (err)
                skb_tx_error(skb);
+       kfree_skb(user_skb);
        kfree_skb(nskb);
        return err;
 }
index d07ab538fc9d37b78082e88906fe41c433467166..7064da92f42037124576069e8ae10eb77203d73b 100644 (file)
@@ -89,7 +89,7 @@ void ovs_flow_stats_update(struct sw_flow *flow, __be16 tcp_flags,
                         * allocated stats as we have already locked them.
                         */
                        if (likely(flow->stats_last_writer != NUMA_NO_NODE)
-                           && likely(!rcu_dereference(flow->stats[node]))) {
+                           && likely(!rcu_access_pointer(flow->stats[node]))) {
                                /* Try to allocate node-specific stats. */
                                struct flow_stats *new_stats;
 
index 6d8f2ec481d9d33927795cfd3f4a59bb7258f128..f7e63f9df7b9152f42715fbed8cab2eb2561cd36 100644 (file)
@@ -148,8 +148,6 @@ struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *ops,
                return ERR_PTR(-ENOMEM);
        }
 
-       spin_lock_init(&vport->stats_lock);
-
        return vport;
 }
 
@@ -268,14 +266,10 @@ void ovs_vport_get_stats(struct vport *vport, struct ovs_vport_stats *stats)
         * netdev-stats can be directly read over netlink-ioctl.
         */
 
-       spin_lock_bh(&vport->stats_lock);
-
-       stats->rx_errors        = vport->err_stats.rx_errors;
-       stats->tx_errors        = vport->err_stats.tx_errors;
-       stats->tx_dropped       = vport->err_stats.tx_dropped;
-       stats->rx_dropped       = vport->err_stats.rx_dropped;
-
-       spin_unlock_bh(&vport->stats_lock);
+       stats->rx_errors  = atomic_long_read(&vport->err_stats.rx_errors);
+       stats->tx_errors  = atomic_long_read(&vport->err_stats.tx_errors);
+       stats->tx_dropped = atomic_long_read(&vport->err_stats.tx_dropped);
+       stats->rx_dropped = atomic_long_read(&vport->err_stats.rx_dropped);
 
        for_each_possible_cpu(i) {
                const struct pcpu_sw_netstats *percpu_stats;
@@ -495,27 +489,24 @@ int ovs_vport_send(struct vport *vport, struct sk_buff *skb)
 static void ovs_vport_record_error(struct vport *vport,
                                   enum vport_err_type err_type)
 {
-       spin_lock(&vport->stats_lock);
-
        switch (err_type) {
        case VPORT_E_RX_DROPPED:
-               vport->err_stats.rx_dropped++;
+               atomic_long_inc(&vport->err_stats.rx_dropped);
                break;
 
        case VPORT_E_RX_ERROR:
-               vport->err_stats.rx_errors++;
+               atomic_long_inc(&vport->err_stats.rx_errors);
                break;
 
        case VPORT_E_TX_DROPPED:
-               vport->err_stats.tx_dropped++;
+               atomic_long_inc(&vport->err_stats.tx_dropped);
                break;
 
        case VPORT_E_TX_ERROR:
-               vport->err_stats.tx_errors++;
+               atomic_long_inc(&vport->err_stats.tx_errors);
                break;
        }
 
-       spin_unlock(&vport->stats_lock);
 }
 
 static void free_vport_rcu(struct rcu_head *rcu)
index 35f89d84b45e2cc828b4e0a2f77e683da6e067c4..0d95b9f5f9c4b025553b9be7e9e1ae27586bd1ca 100644 (file)
@@ -62,10 +62,10 @@ int ovs_vport_send(struct vport *, struct sk_buff *);
 /* The following definitions are for implementers of vport devices: */
 
 struct vport_err_stats {
-       u64 rx_dropped;
-       u64 rx_errors;
-       u64 tx_dropped;
-       u64 tx_errors;
+       atomic_long_t rx_dropped;
+       atomic_long_t rx_errors;
+       atomic_long_t tx_dropped;
+       atomic_long_t tx_errors;
 };
 /**
  * struct vport_portids - array of netlink portids of a vport.
@@ -93,7 +93,6 @@ struct vport_portids {
  * @dp_hash_node: Element in @datapath->ports hash table in datapath.c.
  * @ops: Class structure.
  * @percpu_stats: Points to per-CPU statistics used and maintained by vport
- * @stats_lock: Protects @err_stats;
  * @err_stats: Points to error statistics used and maintained by vport
  */
 struct vport {
@@ -108,7 +107,6 @@ struct vport {
 
        struct pcpu_sw_netstats __percpu *percpu_stats;
 
-       spinlock_t stats_lock;
        struct vport_err_stats err_stats;
 };
 
index 8d9f8042705ad82d8f11050bd3eb1951712eeaf7..87d20f48ff06195766e8ecd20a3fcfae5ccae690 100644 (file)
@@ -240,11 +240,9 @@ static void __fanout_link(struct sock *sk, struct packet_sock *po);
 static int packet_direct_xmit(struct sk_buff *skb)
 {
        struct net_device *dev = skb->dev;
-       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;
 
        if (unlikely(!netif_running(dev) ||
                     !netif_carrier_ok(dev)))
@@ -255,17 +253,13 @@ static int packet_direct_xmit(struct sk_buff *skb)
            __skb_linearize(skb))
                goto drop;
 
-       queue_map = skb_get_queue_mapping(skb);
-       txq = netdev_get_tx_queue(dev, queue_map);
+       txq = skb_get_tx_queue(dev, skb);
 
        local_bh_disable();
 
        HARD_TX_LOCK(dev, txq, smp_processor_id());
-       if (!netif_xmit_frozen_or_drv_stopped(txq)) {
-               ret = ops->ndo_start_xmit(skb, dev);
-               if (ret == NETDEV_TX_OK)
-                       txq_trans_update(txq);
-       }
+       if (!netif_xmit_frozen_or_drv_stopped(txq))
+               ret = netdev_start_xmit(skb, dev, txq, false);
        HARD_TX_UNLOCK(dev, txq);
 
        local_bh_enable();
@@ -632,6 +626,7 @@ static void init_prb_bdqc(struct packet_sock *po,
        p1->tov_in_jiffies = msecs_to_jiffies(p1->retire_blk_tov);
        p1->blk_sizeof_priv = req_u->req3.tp_sizeof_priv;
 
+       p1->max_frame_len = p1->kblk_size - BLK_PLUS_PRIV(p1->blk_sizeof_priv);
        prb_init_ft_ops(p1, req_u);
        prb_setup_retire_blk_timer(po, tx_ring);
        prb_open_block(p1, pbd);
@@ -1942,6 +1937,18 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
                        if ((int)snaplen < 0)
                                snaplen = 0;
                }
+       } else if (unlikely(macoff + snaplen >
+                           GET_PBDQC_FROM_RB(&po->rx_ring)->max_frame_len)) {
+               u32 nval;
+
+               nval = GET_PBDQC_FROM_RB(&po->rx_ring)->max_frame_len - macoff;
+               pr_err_once("tpacket_rcv: packet too big, clamped from %u to %u. macoff=%u\n",
+                           snaplen, nval, macoff);
+               snaplen = nval;
+               if (unlikely((int)snaplen < 0)) {
+                       snaplen = 0;
+                       macoff = GET_PBDQC_FROM_RB(&po->rx_ring)->max_frame_len;
+               }
        }
        spin_lock(&sk->sk_receive_queue.lock);
        h.raw = packet_current_rx_frame(po, skb,
@@ -3783,6 +3790,10 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
                        goto out;
                if (unlikely(req->tp_block_size & (PAGE_SIZE - 1)))
                        goto out;
+               if (po->tp_version >= TPACKET_V3 &&
+                   (int)(req->tp_block_size -
+                         BLK_PLUS_PRIV(req_u->req3.tp_sizeof_priv)) <= 0)
+                       goto out;
                if (unlikely(req->tp_frame_size < po->tp_hdrlen +
                                        po->tp_reserve))
                        goto out;
index eb9580a6b25ff4474a7af54900efbe2579325d00..cdddf6a303996b1a512a7a3896362acc31635f0e 100644 (file)
@@ -29,6 +29,7 @@ struct tpacket_kbdq_core {
        char            *pkblk_start;
        char            *pkblk_end;
        int             kblk_size;
+       unsigned int    max_frame_len;
        unsigned int    knum_blocks;
        uint64_t        knxt_seq_num;
        char            *prev;
index 14c98e48f261ee49656eabb198d62648890b63b3..02a86a27fd846602dd0c9aafd0a045f196e246b4 100644 (file)
@@ -158,6 +158,7 @@ static const struct acpi_device_id rfkill_acpi_match[] = {
        { "BCM2E1A", RFKILL_TYPE_BLUETOOTH },
        { "BCM2E39", RFKILL_TYPE_BLUETOOTH },
        { "BCM2E3D", RFKILL_TYPE_BLUETOOTH },
+       { "BCM2E64", RFKILL_TYPE_BLUETOOTH },
        { "BCM4752", RFKILL_TYPE_GPS },
        { "LNV4752", RFKILL_TYPE_GPS },
        { },
index bc5514211b0cfb4b3d4d42a12eeb03de8e90a2b4..e873d7d9f8571c4d5db2efd70dcdd0c5da792e1c 100644 (file)
@@ -160,7 +160,8 @@ void rose_link_rx_restart(struct sk_buff *skb, struct rose_neigh *neigh, unsigne
                break;
 
        case ROSE_DIAGNOSTIC:
-               printk(KERN_WARNING "ROSE: received diagnostic #%d - %02X %02X %02X\n", skb->data[3], skb->data[4], skb->data[5], skb->data[6]);
+               pr_warn("ROSE: received diagnostic #%d - %3ph\n", skb->data[3],
+                       skb->data + 4);
                break;
 
        default:
index db57458c824c87b463ceff200be22c07df936b73..74c0fcd36838dfc7326eeddb7726483576da0413 100644 (file)
@@ -37,7 +37,7 @@ void rxrpc_UDP_error_report(struct sock *sk)
 
        _enter("%p{%d}", sk, local->debug_id);
 
-       skb = skb_dequeue(&sk->sk_error_queue);
+       skb = sock_dequeue_err_skb(sk);
        if (!skb) {
                _leave("UDP socket errqueue empty");
                return;
@@ -111,18 +111,6 @@ void rxrpc_UDP_error_report(struct sock *sk)
        skb_queue_tail(&trans->error_queue, skb);
        rxrpc_queue_work(&trans->error_handler);
 
-       /* reset and regenerate socket error */
-       spin_lock_bh(&sk->sk_error_queue.lock);
-       sk->sk_err = 0;
-       skb = skb_peek(&sk->sk_error_queue);
-       if (skb) {
-               sk->sk_err = SKB_EXT_ERR(skb)->ee.ee_errno;
-               spin_unlock_bh(&sk->sk_error_queue.lock);
-               sk->sk_error_report(sk);
-       } else {
-               spin_unlock_bh(&sk->sk_error_queue.lock);
-       }
-
        _leave("");
 }
 
index 63b21e580de95d21c60bfeeffac7d2b0aaefaf42..481f89f93789a147fd5979e894e62145f4d9d767 100644 (file)
@@ -45,7 +45,7 @@ int rxrpc_queue_rcv_skb(struct rxrpc_call *call, struct sk_buff *skb,
        struct rxrpc_skb_priv *sp;
        struct rxrpc_sock *rx = call->socket;
        struct sock *sk;
-       int skb_len, ret;
+       int ret;
 
        _enter(",,%d,%d", force, terminal);
 
@@ -101,13 +101,6 @@ int rxrpc_queue_rcv_skb(struct rxrpc_call *call, struct sk_buff *skb,
                        rx->interceptor(sk, call->user_call_ID, skb);
                        spin_unlock_bh(&sk->sk_receive_queue.lock);
                } else {
-
-                       /* Cache the SKB length before we tack it onto the
-                        * receive queue.  Once it is added it no longer
-                        * belongs to us and may be freed by other threads of
-                        * control pulling packets from the queue */
-                       skb_len = skb->len;
-
                        _net("post skb %p", skb);
                        __skb_queue_tail(&sk->sk_receive_queue, skb);
                        spin_unlock_bh(&sk->sk_receive_queue.lock);
index 0566e4606a4ac86710ebbc04a80c9ad1729849cd..f32bcb0949154c5992eeb93e3e6b8ff576812060 100644 (file)
@@ -231,7 +231,7 @@ override:
        if (ret != ACT_P_CREATED)
                return ret;
 
-       police->tcfp_t_c = ktime_to_ns(ktime_get());
+       police->tcfp_t_c = ktime_get_ns();
        police->tcf_index = parm->index ? parm->index :
                tcf_hash_new_index(hinfo);
        h = tcf_hash(police->tcf_index, POL_TAB_MASK);
@@ -279,7 +279,7 @@ static int tcf_act_police(struct sk_buff *skb, const struct tc_action *a,
                        return police->tcfp_result;
                }
 
-               now = ktime_to_ns(ktime_get());
+               now = ktime_get_ns();
                toks = min_t(s64, now - police->tcfp_t_c,
                             police->tcfp_burst);
                if (police->peak_present) {
index ead526467ccae574d6afddb7a5146fc7507e68a9..762a04bb8f6dcbe4627b579ff4081a4cf92adb11 100644 (file)
@@ -159,7 +159,6 @@ struct cbq_sched_data {
        struct cbq_class        *tx_borrowed;
        int                     tx_len;
        psched_time_t           now;            /* Cached timestamp */
-       psched_time_t           now_rt;         /* Cached real time */
        unsigned int            pmask;
 
        struct hrtimer          delay_timer;
@@ -353,12 +352,7 @@ cbq_mark_toplevel(struct cbq_sched_data *q, struct cbq_class *cl)
        int toplevel = q->toplevel;
 
        if (toplevel > cl->level && !(qdisc_is_throttled(cl->q))) {
-               psched_time_t now;
-               psched_tdiff_t incr;
-
-               now = psched_get_time();
-               incr = now - q->now_rt;
-               now = q->now + incr;
+               psched_time_t now = psched_get_time();
 
                do {
                        if (cl->undertime < now) {
@@ -700,8 +694,13 @@ cbq_update(struct cbq_sched_data *q)
        struct cbq_class *this = q->tx_class;
        struct cbq_class *cl = this;
        int len = q->tx_len;
+       psched_time_t now;
 
        q->tx_class = NULL;
+       /* Time integrator. We calculate EOS time
+        * by adding expected packet transmission time.
+        */
+       now = q->now + L2T(&q->link, len);
 
        for ( ; cl; cl = cl->share) {
                long avgidle = cl->avgidle;
@@ -717,7 +716,7 @@ cbq_update(struct cbq_sched_data *q)
                 *      idle = (now - last) - last_pktlen/rate
                 */
 
-               idle = q->now - cl->last;
+               idle = now - cl->last;
                if ((unsigned long)idle > 128*1024*1024) {
                        avgidle = cl->maxidle;
                } else {
@@ -761,7 +760,7 @@ cbq_update(struct cbq_sched_data *q)
                        idle -= L2T(&q->link, len);
                        idle += L2T(cl, len);
 
-                       cl->undertime = q->now + idle;
+                       cl->undertime = now + idle;
                } else {
                        /* Underlimit */
 
@@ -771,7 +770,8 @@ cbq_update(struct cbq_sched_data *q)
                        else
                                cl->avgidle = avgidle;
                }
-               cl->last = q->now;
+               if ((s64)(now - cl->last) > 0)
+                       cl->last = now;
        }
 
        cbq_update_toplevel(q, this, q->tx_borrowed);
@@ -943,31 +943,13 @@ cbq_dequeue(struct Qdisc *sch)
        struct sk_buff *skb;
        struct cbq_sched_data *q = qdisc_priv(sch);
        psched_time_t now;
-       psched_tdiff_t incr;
 
        now = psched_get_time();
-       incr = now - q->now_rt;
-
-       if (q->tx_class) {
-               psched_tdiff_t incr2;
-               /* Time integrator. We calculate EOS time
-                * by adding expected packet transmission time.
-                * If real time is greater, we warp artificial clock,
-                * so that:
-                *
-                * cbq_time = max(real_time, work);
-                */
-               incr2 = L2T(&q->link, q->tx_len);
-               q->now += incr2;
+
+       if (q->tx_class)
                cbq_update(q);
-               if ((incr -= incr2) < 0)
-                       incr = 0;
-               q->now += incr;
-       } else {
-               if (now > q->now)
-                       q->now = now;
-       }
-       q->now_rt = now;
+
+       q->now = now;
 
        for (;;) {
                q->wd_expires = 0;
@@ -1223,7 +1205,6 @@ cbq_reset(struct Qdisc *sch)
        hrtimer_cancel(&q->delay_timer);
        q->toplevel = TC_CBQ_MAXLEVEL;
        q->now = psched_get_time();
-       q->now_rt = q->now;
 
        for (prio = 0; prio <= TC_CBQ_MAXPRIO; prio++)
                q->active[prio] = NULL;
@@ -1407,7 +1388,6 @@ static int cbq_init(struct Qdisc *sch, struct nlattr *opt)
        q->delay_timer.function = cbq_undelay;
        q->toplevel = TC_CBQ_MAXLEVEL;
        q->now = psched_get_time();
-       q->now_rt = q->now;
 
        cbq_link_class(&q->link);
 
index ba32c2b005d0821788f656e8ae05d4d47a862351..e12f997e1b4ca9862f408f6751713c793d747606 100644 (file)
@@ -416,7 +416,7 @@ static void fq_check_throttled(struct fq_sched_data *q, u64 now)
 static struct sk_buff *fq_dequeue(struct Qdisc *sch)
 {
        struct fq_sched_data *q = qdisc_priv(sch);
-       u64 now = ktime_to_ns(ktime_get());
+       u64 now = ktime_get_ns();
        struct fq_flow_head *head;
        struct sk_buff *skb;
        struct fq_flow *f;
@@ -787,7 +787,7 @@ nla_put_failure:
 static int fq_dump_stats(struct Qdisc *sch, struct gnet_dump *d)
 {
        struct fq_sched_data *q = qdisc_priv(sch);
-       u64 now = ktime_to_ns(ktime_get());
+       u64 now = ktime_get_ns();
        struct tc_fq_qd_stats st = {
                .gc_flows               = q->stat_gc_flows,
                .highprio_packets       = q->stat_internal_packets,
index 063b726bf1f8636e3529a2e61d1b43fced918d9c..cc56c8bb9bed7c3487ffd39c7bbed5c445ef144b 100644 (file)
@@ -77,7 +77,8 @@ static unsigned int fq_codel_hash(const struct fq_codel_sched_data *q,
        hash = jhash_3words((__force u32)keys.dst,
                            (__force u32)keys.src ^ keys.ip_proto,
                            (__force u32)keys.ports, q->perturbation);
-       return ((u64)hash * q->flows_cnt) >> 32;
+
+       return reciprocal_scale(hash, q->flows_cnt);
 }
 
 static unsigned int fq_codel_classify(struct sk_buff *skb, struct Qdisc *sch,
index fc04fe93c2da2fa8b43b4be97ccd28dba8ca9e3c..19696ebe9ebc897379b6b9826e339f8ab10ddbc8 100644 (file)
@@ -63,15 +63,18 @@ static inline struct sk_buff *dequeue_skb(struct Qdisc *q)
 
        if (unlikely(skb)) {
                /* check the reason of requeuing without tx lock first */
-               txq = netdev_get_tx_queue(txq->dev, skb_get_queue_mapping(skb));
+               txq = skb_get_tx_queue(txq->dev, skb);
                if (!netif_xmit_frozen_or_stopped(txq)) {
                        q->gso_skb = NULL;
                        q->q.qlen--;
                } else
                        skb = NULL;
        } else {
-               if (!(q->flags & TCQ_F_ONETXQUEUE) || !netif_xmit_frozen_or_stopped(txq))
+               if (!(q->flags & TCQ_F_ONETXQUEUE) || !netif_xmit_frozen_or_stopped(txq)) {
                        skb = q->dequeue(q);
+                       if (skb)
+                               skb = validate_xmit_skb(skb, qdisc_dev(q));
+               }
        }
 
        return skb;
@@ -90,7 +93,7 @@ static inline int handle_dev_cpu_collision(struct sk_buff *skb,
                 * detect it by checking xmit owner and drop the packet when
                 * deadloop is detected. Return OK to try the next skb.
                 */
-               kfree_skb(skb);
+               kfree_skb_list(skb);
                net_warn_ratelimited("Dead loop on netdevice %s, fix it urgently!\n",
                                     dev_queue->dev->name);
                ret = qdisc_qlen(q);
@@ -107,9 +110,9 @@ static inline int handle_dev_cpu_collision(struct sk_buff *skb,
 }
 
 /*
- * Transmit one skb, and handle the return status as required. Holding the
- * __QDISC___STATE_RUNNING bit guarantees that only one CPU can execute this
- * function.
+ * Transmit possibly several skbs, and handle the return status as
+ * required. Holding the __QDISC___STATE_RUNNING bit guarantees that
+ * only one CPU can execute this function.
  *
  * Returns to the caller:
  *                             0  - queue is empty or throttled.
@@ -126,7 +129,7 @@ int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q,
 
        HARD_TX_LOCK(dev, txq, smp_processor_id());
        if (!netif_xmit_frozen_or_stopped(txq))
-               ret = dev_hard_start_xmit(skb, dev, txq);
+               skb = dev_hard_start_xmit(skb, dev, txq, &ret);
 
        HARD_TX_UNLOCK(dev, txq);
 
@@ -183,10 +186,12 @@ static inline int qdisc_restart(struct Qdisc *q)
        skb = dequeue_skb(q);
        if (unlikely(!skb))
                return 0;
+
        WARN_ON_ONCE(skb_dst_is_noref(skb));
+
        root_lock = qdisc_lock(q);
        dev = qdisc_dev(q);
-       txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb));
+       txq = skb_get_tx_queue(dev, skb);
 
        return sch_direct_xmit(skb, q, dev, txq, root_lock);
 }
@@ -616,7 +621,7 @@ void qdisc_reset(struct Qdisc *qdisc)
                ops->reset(qdisc);
 
        if (qdisc->gso_skb) {
-               kfree_skb(qdisc->gso_skb);
+               kfree_skb_list(qdisc->gso_skb);
                qdisc->gso_skb = NULL;
                qdisc->q.qlen = 0;
        }
@@ -652,7 +657,7 @@ void qdisc_destroy(struct Qdisc *qdisc)
        module_put(ops->owner);
        dev_put(qdisc_dev(qdisc));
 
-       kfree_skb(qdisc->gso_skb);
+       kfree_skb_list(qdisc->gso_skb);
        /*
         * gen_estimator est_timer() might access qdisc->q.lock,
         * wait a RCU grace period before freeing qdisc.
index 9f949abcacef1680dcdc15579c7fe56611f21852..aea942ce6008c542982ab503555b925733ede962 100644 (file)
@@ -895,7 +895,7 @@ ok:
 
        if (!sch->q.qlen)
                goto fin;
-       q->now = ktime_to_ns(ktime_get());
+       q->now = ktime_get_ns();
        start_at = jiffies;
 
        next_event = q->now + 5LLU * NSEC_PER_SEC;
@@ -1225,7 +1225,7 @@ static void htb_parent_to_leaf(struct htb_sched *q, struct htb_class *cl,
        parent->un.leaf.q = new_q ? new_q : &noop_qdisc;
        parent->tokens = parent->buffer;
        parent->ctokens = parent->cbuffer;
-       parent->t_c = ktime_to_ns(ktime_get());
+       parent->t_c = ktime_get_ns();
        parent->cmode = HTB_CAN_SEND;
 }
 
@@ -1455,7 +1455,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
                cl->tokens = PSCHED_TICKS2NS(hopt->buffer);
                cl->ctokens = PSCHED_TICKS2NS(hopt->cbuffer);
                cl->mbuffer = 60ULL * NSEC_PER_SEC;     /* 1min */
-               cl->t_c = ktime_to_ns(ktime_get());
+               cl->t_c = ktime_get_ns();
                cl->cmode = HTB_CAN_SEND;
 
                /* attach to the hash list and parent's family */
index 1af2f73906d07aa5bf6f428ffe37b81523178ee4..211db9017c3532d1efac15d57781e97e86ef647e 100644 (file)
@@ -310,11 +310,6 @@ static inline void slot_queue_add(struct sfq_slot *slot, struct sk_buff *skb)
        slot->skblist_prev = skb;
 }
 
-#define        slot_queue_walk(slot, skb)              \
-       for (skb = slot->skblist_next;          \
-            skb != (struct sk_buff *)slot;     \
-            skb = skb->next)
-
 static unsigned int sfq_drop(struct Qdisc *sch)
 {
        struct sfq_sched_data *q = qdisc_priv(sch);
index 18ff634337092d5f8e7cba8fe817542f1455738f..0c39b754083b2028438289ddd8a5a292a1cbf938 100644 (file)
@@ -239,7 +239,7 @@ static struct sk_buff *tbf_dequeue(struct Qdisc *sch)
                s64 ptoks = 0;
                unsigned int len = qdisc_pkt_len(skb);
 
-               now = ktime_to_ns(ktime_get());
+               now = ktime_get_ns();
                toks = min_t(s64, now - q->t_c, q->buffer);
 
                if (tbf_peak_present(q)) {
@@ -292,7 +292,7 @@ static void tbf_reset(struct Qdisc *sch)
 
        qdisc_reset(q->qdisc);
        sch->q.qlen = 0;
-       q->t_c = ktime_to_ns(ktime_get());
+       q->t_c = ktime_get_ns();
        q->tokens = q->buffer;
        q->ptokens = q->mtu;
        qdisc_watchdog_cancel(&q->watchdog);
@@ -431,7 +431,7 @@ static int tbf_init(struct Qdisc *sch, struct nlattr *opt)
        if (opt == NULL)
                return -EINVAL;
 
-       q->t_c = ktime_to_ns(ktime_get());
+       q->t_c = ktime_get_ns();
        qdisc_watchdog_init(&q->watchdog, sch);
        q->qdisc = &noop_qdisc;
 
index bd33793b527e176b07f7bacb77143ed38e32d31c..aaa8d03ed054789f36e184b314d75ba1fd27c6c7 100644 (file)
@@ -301,7 +301,6 @@ restart:
        do {
                struct net_device *slave = qdisc_dev(q);
                struct netdev_queue *slave_txq = netdev_get_tx_queue(slave, 0);
-               const struct net_device_ops *slave_ops = slave->netdev_ops;
 
                if (slave_txq->qdisc_sleeping != q)
                        continue;
@@ -317,8 +316,8 @@ restart:
                                unsigned int length = qdisc_pkt_len(skb);
 
                                if (!netif_xmit_frozen_or_stopped(slave_txq) &&
-                                   slave_ops->ndo_start_xmit(skb, slave) == NETDEV_TX_OK) {
-                                       txq_trans_update(slave_txq);
+                                   netdev_start_xmit(skb, slave, slave_txq, false) ==
+                                   NETDEV_TX_OK) {
                                        __netif_tx_unlock(slave_txq);
                                        master->slaves = NEXT_SLAVE(q);
                                        netif_wake_queue(dev);
index 06a9ee6b2d3a577a73b62028a711f5f801fe13f0..a88b8524846eb0b6a03d7f05f2e8910efd432305 100644 (file)
@@ -813,6 +813,7 @@ void sctp_assoc_control_transport(struct sctp_association *asoc,
                else {
                        dst_release(transport->dst);
                        transport->dst = NULL;
+                       ulp_notify = false;
                }
 
                spc_state = SCTP_ADDR_UNREACHABLE;
@@ -1244,7 +1245,7 @@ static struct sctp_transport *sctp_trans_elect_best(struct sctp_transport *curr,
 {
        u8 score_curr, score_best;
 
-       if (best == NULL)
+       if (best == NULL || curr == best)
                return curr;
 
        score_curr = sctp_trans_score(curr);
@@ -1355,14 +1356,11 @@ static void sctp_select_active_and_retran_path(struct sctp_association *asoc)
                trans_sec = trans_pri;
 
        /* If we failed to find a usable transport, just camp on the
-        * primary or retran, even if they are inactive, if possible
-        * pick a PF iff it's the better choice.
+        * active or pick a PF iff it's the better choice.
         */
        if (trans_pri == NULL) {
-               trans_pri = sctp_trans_elect_best(asoc->peer.primary_path,
-                                                 asoc->peer.retran_path);
-               trans_pri = sctp_trans_elect_best(trans_pri, trans_pf);
-               trans_sec = asoc->peer.primary_path;
+               trans_pri = sctp_trans_elect_best(asoc->peer.active_path, trans_pf);
+               trans_sec = trans_pri;
        }
 
        /* Set the active and retran transports. */
index c1b991294516fd1ef29de13cf24f06c1d63c8be2..b6493b3f11a97f359d0ec70cde2812082f65910f 100644 (file)
@@ -133,9 +133,13 @@ int sctp_rcv(struct sk_buff *skb)
        __skb_pull(skb, skb_transport_offset(skb));
        if (skb->len < sizeof(struct sctphdr))
                goto discard_it;
-       if (!sctp_checksum_disable && !skb_csum_unnecessary(skb) &&
-                 sctp_rcv_checksum(net, skb) < 0)
+
+       skb->csum_valid = 0; /* Previous value not applicable */
+       if (skb_csum_unnecessary(skb))
+               __skb_decr_checksum_unnecessary(skb);
+       else if (!sctp_checksum_disable && sctp_rcv_checksum(net, skb) < 0)
                goto discard_it;
+       skb->csum_valid = 1;
 
        skb_pull(skb, sizeof(struct sctphdr));
 
index 6240834f4b95255a054c2017497d9b07b06b71f7..9d2c6c9facb6a4f4dabee29d8430aaf55b323636 100644 (file)
@@ -366,7 +366,7 @@ static int sctp_v4_available(union sctp_addr *addr, struct sctp_sock *sp)
        if (addr->v4.sin_addr.s_addr != htonl(INADDR_ANY) &&
           ret != RTN_LOCAL &&
           !sp->inet.freebind &&
-          !sysctl_ip_nonlocal_bind)
+          !net->ipv4.sysctl_ip_nonlocal_bind)
                return 0;
 
        if (ipv6_only_sock(sctp_opt2sk(sp)))
index eb71d49e76537f17d48e3eeaa43661fb09788f41..634a2abb5f3a25f15ca99c4737190c1e5e17b27a 100644 (file)
@@ -4243,7 +4243,7 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len,
        transport = asoc->peer.primary_path;
 
        status.sstat_assoc_id = sctp_assoc2id(asoc);
-       status.sstat_state = asoc->state;
+       status.sstat_state = sctp_assoc_to_state(asoc);
        status.sstat_rwnd =  asoc->peer.rwnd;
        status.sstat_unackdata = asoc->unack_data;
 
index 95ee7d8682e7447f45f5ddb0ddbde5fff196c84e..d40f522541aa7c1371f93f346a3af0a777e18c76 100644 (file)
@@ -610,7 +610,7 @@ void sock_release(struct socket *sock)
 }
 EXPORT_SYMBOL(sock_release);
 
-void sock_tx_timestamp(const struct sock *sk, __u8 *tx_flags)
+void __sock_tx_timestamp(const struct sock *sk, __u8 *tx_flags)
 {
        u8 flags = *tx_flags;
 
@@ -626,12 +626,9 @@ void sock_tx_timestamp(const struct sock *sk, __u8 *tx_flags)
        if (sk->sk_tsflags & SOF_TIMESTAMPING_TX_ACK)
                flags |= SKBTX_ACK_TSTAMP;
 
-       if (sock_flag(sk, SOCK_WIFI_STATUS))
-               flags |= SKBTX_WIFI_STATUS;
-
        *tx_flags = flags;
 }
-EXPORT_SYMBOL(sock_tx_timestamp);
+EXPORT_SYMBOL(__sock_tx_timestamp);
 
 static inline int __sock_sendmsg_nosec(struct kiocb *iocb, struct socket *sock,
                                       struct msghdr *msg, size_t size)
@@ -734,8 +731,7 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
        }
 
        memset(&tss, 0, sizeof(tss));
-       if ((sk->sk_tsflags & SOF_TIMESTAMPING_SOFTWARE ||
-            skb_shinfo(skb)->tx_flags & SKBTX_ANY_SW_TSTAMP) &&
+       if ((sk->sk_tsflags & SOF_TIMESTAMPING_SOFTWARE) &&
            ktime_to_timespec_cond(skb->tstamp, tss.ts + 0))
                empty = 0;
        if (shhwtstamps &&
@@ -2602,7 +2598,7 @@ SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args)
  *
  *     This function is called by a protocol handler that wants to
  *     advertise its address family, and have it linked into the
- *     socket interface. The value ops->family coresponds to the
+ *     socket interface. The value ops->family corresponds to the
  *     socket system call protocol family.
  */
 int sock_register(const struct net_proto_family *ops)
index a080c66d819a032233a963512d849f757cc979e2..b8a13caad59a518dddd2a8a50ad3a9a04f363cae 100644 (file)
@@ -7,7 +7,7 @@ obj-$(CONFIG_TIPC) := tipc.o
 tipc-y += addr.o bcast.o bearer.o config.o \
           core.o link.o discover.o msg.o  \
           name_distr.o  subscr.o name_table.o net.o  \
-          netlink.o node.o node_subscr.o port.o ref.o  \
+          netlink.o node.o node_subscr.o \
           socket.o log.o eth_media.o server.o
 
 tipc-$(CONFIG_TIPC_MEDIA_IB)   += ib_media.o
index dd13bfa09333246fb6ba54171fd11ad0cc4fe63f..b2bbe69b25543c5a355286ebb75750c6b5726e1c 100644 (file)
@@ -37,7 +37,6 @@
 
 #include "core.h"
 #include "link.h"
-#include "port.h"
 #include "socket.h"
 #include "msg.h"
 #include "bcast.h"
@@ -300,8 +299,8 @@ void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked)
                tipc_link_push_queue(bcl);
                bclink_set_last_sent();
        }
-       if (unlikely(released && !list_empty(&bcl->waiting_ports)))
-               tipc_link_wakeup_ports(bcl, 0);
+       if (unlikely(released && !skb_queue_empty(&bcl->waiting_sks)))
+               bclink->node.action_flags |= TIPC_WAKEUP_USERS;
 exit:
        tipc_bclink_unlock();
 }
@@ -840,9 +839,10 @@ int tipc_bclink_init(void)
        sprintf(bcbearer->media.name, "tipc-broadcast");
 
        spin_lock_init(&bclink->lock);
-       INIT_LIST_HEAD(&bcl->waiting_ports);
+       __skb_queue_head_init(&bcl->waiting_sks);
        bcl->next_out_no = 1;
        spin_lock_init(&bclink->node.lock);
+       __skb_queue_head_init(&bclink->node.waiting_sks);
        bcl->owner = &bclink->node;
        bcl->max_pkt = MAX_PKT_DEFAULT_MCAST;
        tipc_link_set_queue_limits(bcl, BCLINK_WIN_DEFAULT);
index 2b42403ad33a690221456ff25fb4be50a2235255..876f4c6a2631b35eba2b9927430b30c34d125c87 100644 (file)
@@ -35,7 +35,7 @@
  */
 
 #include "core.h"
-#include "port.h"
+#include "socket.h"
 #include "name_table.h"
 #include "config.h"
 #include "server.h"
@@ -266,7 +266,7 @@ struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area
                rep_tlv_buf = tipc_media_get_names();
                break;
        case TIPC_CMD_SHOW_PORTS:
-               rep_tlv_buf = tipc_port_get_ports();
+               rep_tlv_buf = tipc_sk_socks_show();
                break;
        case TIPC_CMD_SHOW_STATS:
                rep_tlv_buf = tipc_show_stats();
index 676d18015dd82efa0346f6bed2bf0d7f5489f1f6..a5737b8407ddbf63f9ecfb024bde3b079f979098 100644 (file)
  */
 
 #include "core.h"
-#include "ref.h"
 #include "name_table.h"
 #include "subscr.h"
 #include "config.h"
-#include "port.h"
+#include "socket.h"
 
 #include <linux/module.h>
 
@@ -85,7 +84,7 @@ static void tipc_core_stop(void)
        tipc_netlink_stop();
        tipc_subscr_stop();
        tipc_nametbl_stop();
-       tipc_ref_table_stop();
+       tipc_sk_ref_table_stop();
        tipc_socket_stop();
        tipc_unregister_sysctl();
 }
@@ -99,7 +98,7 @@ static int tipc_core_start(void)
 
        get_random_bytes(&tipc_random, sizeof(tipc_random));
 
-       err = tipc_ref_table_init(tipc_max_ports, tipc_random);
+       err = tipc_sk_ref_table_init(tipc_max_ports, tipc_random);
        if (err)
                goto out_reftbl;
 
@@ -139,7 +138,7 @@ out_socket:
 out_netlink:
        tipc_nametbl_stop();
 out_nametbl:
-       tipc_ref_table_stop();
+       tipc_sk_ref_table_stop();
 out_reftbl:
        return err;
 }
index bb26ed1ee966c84c66fc7322877d80f763047e5a..f773b148722f7e51195d525a55e2ae18577c3c3e 100644 (file)
@@ -81,6 +81,7 @@ extern u32 tipc_own_addr __read_mostly;
 extern int tipc_max_ports __read_mostly;
 extern int tipc_net_id __read_mostly;
 extern int sysctl_tipc_rmem[3] __read_mostly;
+extern int sysctl_tipc_named_timeout __read_mostly;
 
 /*
  * Other global variables
@@ -187,8 +188,11 @@ static inline void k_term_timer(struct timer_list *timer)
 
 struct tipc_skb_cb {
        void *handle;
-       bool deferred;
        struct sk_buff *tail;
+       bool deferred;
+       bool wakeup_pending;
+       u16 chain_sz;
+       u16 chain_imp;
 };
 
 #define TIPC_SKB_CB(__skb) ((struct tipc_skb_cb *)&((__skb)->cb[0]))
index fb1485dc6736ec84719c262334ead93d659bb7c4..65410e18b8a6e90f52554276db9bdd927d2a63ba 100644 (file)
@@ -36,7 +36,6 @@
 
 #include "core.h"
 #include "link.h"
-#include "port.h"
 #include "socket.h"
 #include "name_distr.h"
 #include "discover.h"
@@ -275,7 +274,7 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr,
        link_init_max_pkt(l_ptr);
 
        l_ptr->next_out_no = 1;
-       INIT_LIST_HEAD(&l_ptr->waiting_ports);
+       __skb_queue_head_init(&l_ptr->waiting_sks);
 
        link_reset_statistics(l_ptr);
 
@@ -322,66 +321,47 @@ void tipc_link_delete_list(unsigned int bearer_id, bool shutting_down)
 }
 
 /**
- * link_schedule_port - schedule port for deferred sending
- * @l_ptr: pointer to link
- * @origport: reference to sending port
- * @sz: amount of data to be sent
- *
- * Schedules port for renewed sending of messages after link congestion
- * has abated.
+ * link_schedule_user - schedule user for wakeup after congestion
+ * @link: congested link
+ * @oport: sending port
+ * @chain_sz: size of buffer chain that was attempted sent
+ * @imp: importance of message attempted sent
+ * Create pseudo msg to send back to user when congestion abates
  */
-static int link_schedule_port(struct tipc_link *l_ptr, u32 origport, u32 sz)
+static bool link_schedule_user(struct tipc_link *link, u32 oport,
+                              uint chain_sz, uint imp)
 {
-       struct tipc_port *p_ptr;
-       struct tipc_sock *tsk;
+       struct sk_buff *buf;
 
-       spin_lock_bh(&tipc_port_list_lock);
-       p_ptr = tipc_port_lock(origport);
-       if (p_ptr) {
-               if (!list_empty(&p_ptr->wait_list))
-                       goto exit;
-               tsk = tipc_port_to_sock(p_ptr);
-               tsk->link_cong = 1;
-               p_ptr->waiting_pkts = 1 + ((sz - 1) / l_ptr->max_pkt);
-               list_add_tail(&p_ptr->wait_list, &l_ptr->waiting_ports);
-               l_ptr->stats.link_congs++;
-exit:
-               tipc_port_unlock(p_ptr);
-       }
-       spin_unlock_bh(&tipc_port_list_lock);
-       return -ELINKCONG;
+       buf = tipc_msg_create(SOCK_WAKEUP, 0, INT_H_SIZE, 0, tipc_own_addr,
+                             tipc_own_addr, oport, 0, 0);
+       if (!buf)
+               return false;
+       TIPC_SKB_CB(buf)->chain_sz = chain_sz;
+       TIPC_SKB_CB(buf)->chain_imp = imp;
+       __skb_queue_tail(&link->waiting_sks, buf);
+       link->stats.link_congs++;
+       return true;
 }
 
-void tipc_link_wakeup_ports(struct tipc_link *l_ptr, int all)
+/**
+ * link_prepare_wakeup - prepare users for wakeup after congestion
+ * @link: congested link
+ * Move a number of waiting users, as permitted by available space in
+ * the send queue, from link wait queue to node wait queue for wakeup
+ */
+static void link_prepare_wakeup(struct tipc_link *link)
 {
-       struct tipc_port *p_ptr;
-       struct tipc_sock *tsk;
-       struct tipc_port *temp_p_ptr;
-       int win = l_ptr->queue_limit[0] - l_ptr->out_queue_size;
-
-       if (all)
-               win = 100000;
-       if (win <= 0)
-               return;
-       if (!spin_trylock_bh(&tipc_port_list_lock))
-               return;
-       if (link_congested(l_ptr))
-               goto exit;
-       list_for_each_entry_safe(p_ptr, temp_p_ptr, &l_ptr->waiting_ports,
-                                wait_list) {
-               if (win <= 0)
+       struct sk_buff_head *wq = &link->waiting_sks;
+       struct sk_buff *buf;
+       uint pend_qsz = link->out_queue_size;
+
+       for (buf = skb_peek(wq); buf; buf = skb_peek(wq)) {
+               if (pend_qsz >= link->queue_limit[TIPC_SKB_CB(buf)->chain_imp])
                        break;
-               tsk = tipc_port_to_sock(p_ptr);
-               list_del_init(&p_ptr->wait_list);
-               spin_lock_bh(p_ptr->lock);
-               tsk->link_cong = 0;
-               tipc_sock_wakeup(tsk);
-               win -= p_ptr->waiting_pkts;
-               spin_unlock_bh(p_ptr->lock);
+               pend_qsz += TIPC_SKB_CB(buf)->chain_sz;
+               __skb_queue_tail(&link->owner->waiting_sks, __skb_dequeue(wq));
        }
-
-exit:
-       spin_unlock_bh(&tipc_port_list_lock);
 }
 
 /**
@@ -423,6 +403,7 @@ void tipc_link_reset(struct tipc_link *l_ptr)
        u32 prev_state = l_ptr->state;
        u32 checkpoint = l_ptr->next_in_no;
        int was_active_link = tipc_link_is_active(l_ptr);
+       struct tipc_node *owner = l_ptr->owner;
 
        msg_set_session(l_ptr->pmsg, ((msg_session(l_ptr->pmsg) + 1) & 0xffff));
 
@@ -450,9 +431,10 @@ void tipc_link_reset(struct tipc_link *l_ptr)
        kfree_skb(l_ptr->proto_msg_queue);
        l_ptr->proto_msg_queue = NULL;
        kfree_skb_list(l_ptr->oldest_deferred_in);
-       if (!list_empty(&l_ptr->waiting_ports))
-               tipc_link_wakeup_ports(l_ptr, 1);
-
+       if (!skb_queue_empty(&l_ptr->waiting_sks)) {
+               skb_queue_splice_init(&l_ptr->waiting_sks, &owner->waiting_sks);
+               owner->action_flags |= TIPC_WAKEUP_USERS;
+       }
        l_ptr->retransm_queue_head = 0;
        l_ptr->retransm_queue_size = 0;
        l_ptr->last_out = NULL;
@@ -688,19 +670,23 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event)
 static int tipc_link_cong(struct tipc_link *link, struct sk_buff *buf)
 {
        struct tipc_msg *msg = buf_msg(buf);
-       uint psz = msg_size(msg);
        uint imp = tipc_msg_tot_importance(msg);
        u32 oport = msg_tot_origport(msg);
 
-       if (likely(imp <= TIPC_CRITICAL_IMPORTANCE)) {
-               if (!msg_errcode(msg) && !msg_reroute_cnt(msg)) {
-                       link_schedule_port(link, oport, psz);
-                       return -ELINKCONG;
-               }
-       } else {
+       if (unlikely(imp > TIPC_CRITICAL_IMPORTANCE)) {
                pr_warn("%s<%s>, send queue full", link_rst_msg, link->name);
                tipc_link_reset(link);
+               goto drop;
        }
+       if (unlikely(msg_errcode(msg)))
+               goto drop;
+       if (unlikely(msg_reroute_cnt(msg)))
+               goto drop;
+       if (TIPC_SKB_CB(buf)->wakeup_pending)
+               return -ELINKCONG;
+       if (link_schedule_user(link, oport, TIPC_SKB_CB(buf)->chain_sz, imp))
+               return -ELINKCONG;
+drop:
        kfree_skb_list(buf);
        return -EHOSTUNREACH;
 }
@@ -1202,8 +1188,10 @@ void tipc_rcv(struct sk_buff *head, struct tipc_bearer *b_ptr)
                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 (released && !skb_queue_empty(&l_ptr->waiting_sks)) {
+                       link_prepare_wakeup(l_ptr);
+                       l_ptr->owner->action_flags |= TIPC_WAKEUP_USERS;
+               }
 
                /* Process the incoming packet */
                if (unlikely(!link_working_working(l_ptr))) {
index 782983ccd323a8f4df659765f76888ec3faebc7a..b567a3427fda46e05a692b606f424da1a60eaa93 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * net/tipc/link.h: Include file for TIPC link code
  *
- * Copyright (c) 1995-2006, 2013, Ericsson AB
+ * Copyright (c) 1995-2006, 2013-2014, Ericsson AB
  * Copyright (c) 2004-2005, 2010-2011, Wind River Systems
  * All rights reserved.
  *
@@ -133,7 +133,7 @@ struct tipc_stats {
  * @retransm_queue_size: number of messages to retransmit
  * @retransm_queue_head: sequence number of first message to retransmit
  * @next_out: ptr to first unsent outbound message in queue
- * @waiting_ports: linked list of ports waiting for link congestion to abate
+ * @waiting_sks: linked list of sockets waiting for link congestion to abate
  * @long_msg_seq_no: next identifier to use for outbound fragmented messages
  * @reasm_buf: head of partially reassembled inbound message fragments
  * @stats: collects statistics regarding link activity
@@ -194,7 +194,7 @@ struct tipc_link {
        u32 retransm_queue_size;
        u32 retransm_queue_head;
        struct sk_buff *next_out;
-       struct list_head waiting_ports;
+       struct sk_buff_head waiting_sks;
 
        /* Fragmentation/reassembly */
        u32 long_msg_seq_no;
@@ -235,7 +235,6 @@ void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int prob,
 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);
-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,
                          struct sk_buff *start, u32 retransmits);
index 9680be6d388a2b77a80e930f1092d6f6c3df13f3..74745a47d72ae1c0ce84c6ff5b096682410a0789 100644 (file)
@@ -56,8 +56,35 @@ void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type, u32 hsize,
        msg_set_size(m, hsize);
        msg_set_prevnode(m, tipc_own_addr);
        msg_set_type(m, type);
-       msg_set_orignode(m, tipc_own_addr);
-       msg_set_destnode(m, destnode);
+       if (hsize > SHORT_H_SIZE) {
+               msg_set_orignode(m, tipc_own_addr);
+               msg_set_destnode(m, destnode);
+       }
+}
+
+struct sk_buff *tipc_msg_create(uint user, uint type, uint hdr_sz,
+                               uint data_sz, u32 dnode, u32 onode,
+                               u32 dport, u32 oport, int errcode)
+{
+       struct tipc_msg *msg;
+       struct sk_buff *buf;
+
+       buf = tipc_buf_acquire(hdr_sz + data_sz);
+       if (unlikely(!buf))
+               return NULL;
+
+       msg = buf_msg(buf);
+       tipc_msg_init(msg, user, type, hdr_sz, dnode);
+       msg_set_size(msg, hdr_sz + data_sz);
+       msg_set_prevnode(msg, onode);
+       msg_set_origport(msg, oport);
+       msg_set_destport(msg, dport);
+       msg_set_errcode(msg, errcode);
+       if (hdr_sz > SHORT_H_SIZE) {
+               msg_set_orignode(msg, onode);
+               msg_set_destnode(msg, dnode);
+       }
+       return buf;
 }
 
 /* tipc_buf_append(): Append a buffer to the fragment list of another buffer
@@ -155,7 +182,7 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct iovec const *iov,
        struct sk_buff *buf, *prev;
        char *pktpos;
        int rc;
-
+       uint chain_sz = 0;
        msg_set_size(mhdr, msz);
 
        /* No fragmentation needed? */
@@ -166,6 +193,7 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct iovec const *iov,
                        return -ENOMEM;
                skb_copy_to_linear_data(buf, mhdr, mhsz);
                pktpos = buf->data + mhsz;
+               TIPC_SKB_CB(buf)->chain_sz = 1;
                if (!dsz || !memcpy_fromiovecend(pktpos, iov, offset, dsz))
                        return dsz;
                rc = -EFAULT;
@@ -182,6 +210,7 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct iovec const *iov,
        *chain = buf = tipc_buf_acquire(pktmax);
        if (!buf)
                return -ENOMEM;
+       chain_sz = 1;
        pktpos = buf->data;
        skb_copy_to_linear_data(buf, &pkthdr, INT_H_SIZE);
        pktpos += INT_H_SIZE;
@@ -215,6 +244,7 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct iovec const *iov,
                        rc = -ENOMEM;
                        goto error;
                }
+               chain_sz++;
                prev->next = buf;
                msg_set_type(&pkthdr, FRAGMENT);
                msg_set_size(&pkthdr, pktsz);
@@ -224,7 +254,7 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct iovec const *iov,
                pktrem = pktsz - INT_H_SIZE;
 
        } while (1);
-
+       TIPC_SKB_CB(*chain)->chain_sz = chain_sz;
        msg_set_type(buf_msg(buf), LAST_FRAGMENT);
        return dsz;
 error:
index 462fa194a6afe5e2f6f759d4a04846d6e26ef32e..0ea7b695ac4d891a7556ae2f08110d11306369f9 100644 (file)
@@ -442,6 +442,7 @@ static inline struct tipc_msg *msg_get_wrapped(struct tipc_msg *m)
 #define  NAME_DISTRIBUTOR     11
 #define  MSG_FRAGMENTER       12
 #define  LINK_CONFIG          13
+#define  SOCK_WAKEUP          14       /* pseudo user */
 
 /*
  *  Connection management protocol message types
@@ -732,6 +733,10 @@ int tipc_msg_eval(struct sk_buff *buf, u32 *dnode);
 void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type, u32 hsize,
                   u32 destnode);
 
+struct sk_buff *tipc_msg_create(uint user, uint type, uint hdr_sz,
+                               uint data_sz, u32 dnode, u32 onode,
+                               u32 dport, u32 oport, int errcode);
+
 int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf);
 
 bool tipc_msg_bundle(struct sk_buff *bbuf, struct sk_buff *buf, u32 mtu);
index dcc15bcd569279a96b74cc052ee140e6f8e1bf3b..780ef710a849b0e4c58c5733b6f552c4e6552ae8 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * net/tipc/name_distr.c: TIPC name distribution code
  *
- * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2000-2006, 2014, Ericsson AB
  * Copyright (c) 2005, 2010-2011, Wind River Systems
  * All rights reserved.
  *
@@ -71,6 +71,21 @@ static struct publ_list *publ_lists[] = {
 };
 
 
+int sysctl_tipc_named_timeout __read_mostly = 2000;
+
+/**
+ * struct tipc_dist_queue - queue holding deferred name table updates
+ */
+static struct list_head tipc_dist_queue = LIST_HEAD_INIT(tipc_dist_queue);
+
+struct distr_queue_item {
+       struct distr_item i;
+       u32 dtype;
+       u32 node;
+       unsigned long expires;
+       struct list_head next;
+};
+
 /**
  * publ_to_item - add publication info to a publication message
  */
@@ -262,55 +277,105 @@ static void named_purge_publ(struct publication *publ)
        kfree(p);
 }
 
+/**
+ * tipc_update_nametbl - try to process a nametable update and notify
+ *                      subscribers
+ *
+ * tipc_nametbl_lock must be held.
+ * Returns the publication item if successful, otherwise NULL.
+ */
+struct publication *tipc_update_nametbl(struct distr_item *i, u32 node,
+                                       u32 dtype)
+{
+       struct publication *publ = NULL;
+
+       if (dtype == PUBLICATION) {
+               publ = tipc_nametbl_insert_publ(ntohl(i->type), ntohl(i->lower),
+                                               ntohl(i->upper),
+                                               TIPC_CLUSTER_SCOPE, node,
+                                               ntohl(i->ref), ntohl(i->key));
+               if (publ) {
+                       tipc_nodesub_subscribe(&publ->subscr, node, publ,
+                                              (net_ev_handler)
+                                              named_purge_publ);
+               }
+       } else if (dtype == WITHDRAWAL) {
+               publ = tipc_nametbl_remove_publ(ntohl(i->type), ntohl(i->lower),
+                                               node, ntohl(i->ref),
+                                               ntohl(i->key));
+               if (publ) {
+                       tipc_nodesub_unsubscribe(&publ->subscr);
+                       kfree(publ);
+               }
+       } else {
+               pr_warn("Unrecognized name table message received\n");
+       }
+       return publ;
+}
+
+/**
+ * tipc_named_add_backlog - add a failed name table update to the backlog
+ *
+ */
+static void tipc_named_add_backlog(struct distr_item *i, u32 type, u32 node)
+{
+       struct distr_queue_item *e;
+       unsigned long now = get_jiffies_64();
+
+       e = kzalloc(sizeof(*e), GFP_ATOMIC);
+       if (!e)
+               return;
+       e->dtype = type;
+       e->node = node;
+       e->expires = now + msecs_to_jiffies(sysctl_tipc_named_timeout);
+       memcpy(e, i, sizeof(*i));
+       list_add_tail(&e->next, &tipc_dist_queue);
+}
+
+/**
+ * tipc_named_process_backlog - try to process any pending name table updates
+ * from the network.
+ */
+void tipc_named_process_backlog(void)
+{
+       struct distr_queue_item *e, *tmp;
+       char addr[16];
+       unsigned long now = get_jiffies_64();
+
+       list_for_each_entry_safe(e, tmp, &tipc_dist_queue, next) {
+               if (time_after(e->expires, now)) {
+                       if (!tipc_update_nametbl(&e->i, e->node, e->dtype))
+                               continue;
+               } else {
+                       tipc_addr_string_fill(addr, e->node);
+                       pr_warn_ratelimited("Dropping name table update (%d) of {%u, %u, %u} from %s key=%u\n",
+                                           e->dtype, ntohl(e->i.type),
+                                           ntohl(e->i.lower),
+                                           ntohl(e->i.upper),
+                                           addr, ntohl(e->i.key));
+               }
+               list_del(&e->next);
+               kfree(e);
+       }
+}
+
 /**
  * tipc_named_rcv - process name table update message sent by another node
  */
 void tipc_named_rcv(struct sk_buff *buf)
 {
-       struct publication *publ;
        struct tipc_msg *msg = buf_msg(buf);
        struct distr_item *item = (struct distr_item *)msg_data(msg);
        u32 count = msg_data_sz(msg) / ITEM_SIZE;
+       u32 node = msg_orignode(msg);
 
        write_lock_bh(&tipc_nametbl_lock);
        while (count--) {
-               if (msg_type(msg) == PUBLICATION) {
-                       publ = tipc_nametbl_insert_publ(ntohl(item->type),
-                                                       ntohl(item->lower),
-                                                       ntohl(item->upper),
-                                                       TIPC_CLUSTER_SCOPE,
-                                                       msg_orignode(msg),
-                                                       ntohl(item->ref),
-                                                       ntohl(item->key));
-                       if (publ) {
-                               tipc_nodesub_subscribe(&publ->subscr,
-                                                      msg_orignode(msg),
-                                                      publ,
-                                                      (net_ev_handler)
-                                                      named_purge_publ);
-                       }
-               } else if (msg_type(msg) == WITHDRAWAL) {
-                       publ = tipc_nametbl_remove_publ(ntohl(item->type),
-                                                       ntohl(item->lower),
-                                                       msg_orignode(msg),
-                                                       ntohl(item->ref),
-                                                       ntohl(item->key));
-
-                       if (publ) {
-                               tipc_nodesub_unsubscribe(&publ->subscr);
-                               kfree(publ);
-                       } else {
-                               pr_err("Unable to remove publication by node 0x%x\n"
-                                      " (type=%u, lower=%u, ref=%u, key=%u)\n",
-                                      msg_orignode(msg), ntohl(item->type),
-                                      ntohl(item->lower), ntohl(item->ref),
-                                      ntohl(item->key));
-                       }
-               } else {
-                       pr_warn("Unrecognized name table message received\n");
-               }
+               if (!tipc_update_nametbl(item, node, msg_type(msg)))
+                       tipc_named_add_backlog(item, msg_type(msg), node);
                item++;
        }
+       tipc_named_process_backlog();
        write_unlock_bh(&tipc_nametbl_lock);
        kfree_skb(buf);
 }
index 8afe32b7fc9a0b6a2b9f78657fd13756eae0b465..b9e75feb3434e76fc96a5e71a07e94fbcc709888 100644 (file)
@@ -73,5 +73,6 @@ void named_cluster_distribute(struct sk_buff *buf);
 void tipc_named_node_up(u32 dnode);
 void tipc_named_rcv(struct sk_buff *buf);
 void tipc_named_reinit(void);
+void tipc_named_process_backlog(void);
 
 #endif
index 9d7d37d95187c77d9d7490ce7aec4de147a9f2fd..3a6a0a7c0759f01ad06b7c8d9b08a6c8d98e4ca9 100644 (file)
@@ -39,7 +39,6 @@
 #include "name_table.h"
 #include "name_distr.h"
 #include "subscr.h"
-#include "port.h"
 
 #define TIPC_NAMETBL_SIZE 1024         /* must be a power of 2 */
 
@@ -262,8 +261,6 @@ static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq,
 
                /* Lower end overlaps existing entry => need an exact match */
                if ((sseq->lower != lower) || (sseq->upper != upper)) {
-                       pr_warn("Cannot publish {%u,%u,%u}, overlap error\n",
-                               type, lower, upper);
                        return NULL;
                }
 
@@ -285,8 +282,6 @@ static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq,
                /* Fail if upper end overlaps into an existing entry */
                if ((inspos < nseq->first_free) &&
                    (upper >= nseq->sseqs[inspos].lower)) {
-                       pr_warn("Cannot publish {%u,%u,%u}, overlap error\n",
-                               type, lower, upper);
                        return NULL;
                }
 
@@ -678,6 +673,8 @@ struct publication *tipc_nametbl_publish(u32 type, u32 lower, u32 upper,
        if (likely(publ)) {
                table.local_publ_count++;
                buf = tipc_named_publish(publ);
+               /* Any pending external events? */
+               tipc_named_process_backlog();
        }
        write_unlock_bh(&tipc_nametbl_lock);
 
@@ -699,6 +696,8 @@ int tipc_nametbl_withdraw(u32 type, u32 lower, u32 ref, u32 key)
        if (likely(publ)) {
                table.local_publ_count--;
                buf = tipc_named_withdraw(publ);
+               /* Any pending external events? */
+               tipc_named_process_backlog();
                write_unlock_bh(&tipc_nametbl_lock);
                list_del_init(&publ->pport_list);
                kfree(publ);
index 7fcc94998feae6eb1427dd25ac965fece340227a..93b9944a6a8bb1e94c332b8bd5e5f641d90899d8 100644 (file)
@@ -38,7 +38,6 @@
 #include "net.h"
 #include "name_distr.h"
 #include "subscr.h"
-#include "port.h"
 #include "socket.h"
 #include "node.h"
 #include "config.h"
@@ -111,7 +110,7 @@ int tipc_net_start(u32 addr)
 
        tipc_own_addr = addr;
        tipc_named_reinit();
-       tipc_port_reinit();
+       tipc_sk_reinit();
        res = tipc_bclink_init();
        if (res)
                return res;
index f7069299943f847f7853a3bb9e5cf781e6caf9b8..17e6378c4dfe479790d085916cb5bfe40b445ae9 100644 (file)
@@ -38,6 +38,7 @@
 #include "config.h"
 #include "node.h"
 #include "name_distr.h"
+#include "socket.h"
 
 #define NODE_HTABLE_SIZE 512
 
@@ -50,6 +51,13 @@ static u32 tipc_num_nodes;
 static u32 tipc_num_links;
 static DEFINE_SPINLOCK(node_list_lock);
 
+struct tipc_sock_conn {
+       u32 port;
+       u32 peer_port;
+       u32 peer_node;
+       struct list_head list;
+};
+
 /*
  * A trivial power-of-two bitmask technique is used for speed, since this
  * operation is done for every incoming TIPC packet. The number of hash table
@@ -100,6 +108,8 @@ struct tipc_node *tipc_node_create(u32 addr)
        INIT_HLIST_NODE(&n_ptr->hash);
        INIT_LIST_HEAD(&n_ptr->list);
        INIT_LIST_HEAD(&n_ptr->nsub);
+       INIT_LIST_HEAD(&n_ptr->conn_sks);
+       __skb_queue_head_init(&n_ptr->waiting_sks);
 
        hlist_add_head_rcu(&n_ptr->hash, &node_htable[tipc_hashfn(addr)]);
 
@@ -136,6 +146,71 @@ void tipc_node_stop(void)
        spin_unlock_bh(&node_list_lock);
 }
 
+int tipc_node_add_conn(u32 dnode, u32 port, u32 peer_port)
+{
+       struct tipc_node *node;
+       struct tipc_sock_conn *conn;
+
+       if (in_own_node(dnode))
+               return 0;
+
+       node = tipc_node_find(dnode);
+       if (!node) {
+               pr_warn("Connecting sock to node 0x%x failed\n", dnode);
+               return -EHOSTUNREACH;
+       }
+       conn = kmalloc(sizeof(*conn), GFP_ATOMIC);
+       if (!conn)
+               return -EHOSTUNREACH;
+       conn->peer_node = dnode;
+       conn->port = port;
+       conn->peer_port = peer_port;
+
+       tipc_node_lock(node);
+       list_add_tail(&conn->list, &node->conn_sks);
+       tipc_node_unlock(node);
+       return 0;
+}
+
+void tipc_node_remove_conn(u32 dnode, u32 port)
+{
+       struct tipc_node *node;
+       struct tipc_sock_conn *conn, *safe;
+
+       if (in_own_node(dnode))
+               return;
+
+       node = tipc_node_find(dnode);
+       if (!node)
+               return;
+
+       tipc_node_lock(node);
+       list_for_each_entry_safe(conn, safe, &node->conn_sks, list) {
+               if (port != conn->port)
+                       continue;
+               list_del(&conn->list);
+               kfree(conn);
+       }
+       tipc_node_unlock(node);
+}
+
+void tipc_node_abort_sock_conns(struct list_head *conns)
+{
+       struct tipc_sock_conn *conn, *safe;
+       struct sk_buff *buf;
+
+       list_for_each_entry_safe(conn, safe, conns, list) {
+               buf = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE, TIPC_CONN_MSG,
+                                     SHORT_H_SIZE, 0, tipc_own_addr,
+                                     conn->peer_node, conn->port,
+                                     conn->peer_port, TIPC_ERR_NO_NODE);
+               if (likely(buf))
+                       tipc_sk_rcv(buf);
+               list_del(&conn->list);
+               kfree(conn);
+       }
+}
+
 /**
  * tipc_node_link_up - handle addition of link
  *
@@ -474,6 +549,8 @@ int tipc_node_get_linkname(u32 bearer_id, u32 addr, char *linkname, size_t len)
 void tipc_node_unlock(struct tipc_node *node)
 {
        LIST_HEAD(nsub_list);
+       LIST_HEAD(conn_sks);
+       struct sk_buff_head waiting_sks;
        u32 addr = 0;
 
        if (likely(!node->action_flags)) {
@@ -481,8 +558,14 @@ void tipc_node_unlock(struct tipc_node *node)
                return;
        }
 
+       __skb_queue_head_init(&waiting_sks);
+       if (node->action_flags & TIPC_WAKEUP_USERS) {
+               skb_queue_splice_init(&node->waiting_sks, &waiting_sks);
+               node->action_flags &= ~TIPC_WAKEUP_USERS;
+       }
        if (node->action_flags & TIPC_NOTIFY_NODE_DOWN) {
                list_replace_init(&node->nsub, &nsub_list);
+               list_replace_init(&node->conn_sks, &conn_sks);
                node->action_flags &= ~TIPC_NOTIFY_NODE_DOWN;
        }
        if (node->action_flags & TIPC_NOTIFY_NODE_UP) {
@@ -491,8 +574,15 @@ void tipc_node_unlock(struct tipc_node *node)
        }
        spin_unlock_bh(&node->lock);
 
+       while (!skb_queue_empty(&waiting_sks))
+               tipc_sk_rcv(__skb_dequeue(&waiting_sks));
+
+       if (!list_empty(&conn_sks))
+               tipc_node_abort_sock_conns(&conn_sks);
+
        if (!list_empty(&nsub_list))
                tipc_nodesub_notify(&nsub_list);
+
        if (addr)
                tipc_named_node_up(addr);
 }
index b61716a8218e583b6a01f711cfb3a7de950d3569..522d6f3157b32cb9aa2d28086700728216e17e81 100644 (file)
@@ -58,7 +58,8 @@ enum {
        TIPC_WAIT_PEER_LINKS_DOWN       = (1 << 1),
        TIPC_WAIT_OWN_LINKS_DOWN        = (1 << 2),
        TIPC_NOTIFY_NODE_DOWN           = (1 << 3),
-       TIPC_NOTIFY_NODE_UP             = (1 << 4)
+       TIPC_NOTIFY_NODE_UP             = (1 << 4),
+       TIPC_WAKEUP_USERS               = (1 << 5)
 };
 
 /**
@@ -115,6 +116,8 @@ struct tipc_node {
        int working_links;
        u32 signature;
        struct list_head nsub;
+       struct sk_buff_head waiting_sks;
+       struct list_head conn_sks;
        struct rcu_head rcu;
 };
 
@@ -133,6 +136,8 @@ struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space)
 struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space);
 int tipc_node_get_linkname(u32 bearer_id, u32 node, char *linkname, size_t len);
 void tipc_node_unlock(struct tipc_node *node);
+int tipc_node_add_conn(u32 dnode, u32 port, u32 peer_port);
+void tipc_node_remove_conn(u32 dnode, u32 port);
 
 static inline void tipc_node_lock(struct tipc_node *node)
 {
diff --git a/net/tipc/port.c b/net/tipc/port.c
deleted file mode 100644 (file)
index 7e096a5..0000000
+++ /dev/null
@@ -1,514 +0,0 @@
-/*
- * net/tipc/port.c: TIPC port code
- *
- * Copyright (c) 1992-2007, 2014, Ericsson AB
- * Copyright (c) 2004-2008, 2010-2013, Wind River Systems
- * 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.
- */
-
-#include "core.h"
-#include "config.h"
-#include "port.h"
-#include "name_table.h"
-#include "socket.h"
-
-/* Connection management: */
-#define PROBING_INTERVAL 3600000       /* [ms] => 1 h */
-
-#define MAX_REJECT_SIZE 1024
-
-DEFINE_SPINLOCK(tipc_port_list_lock);
-
-static LIST_HEAD(ports);
-static void port_handle_node_down(unsigned long ref);
-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);
-
-/**
- * tipc_port_peer_msg - verify message was sent by connected port's peer
- *
- * Handles cases where the node's network address has changed from
- * the default of <0.0.0> to its configured setting.
- */
-int tipc_port_peer_msg(struct tipc_port *p_ptr, struct tipc_msg *msg)
-{
-       u32 peernode;
-       u32 orignode;
-
-       if (msg_origport(msg) != tipc_port_peerport(p_ptr))
-               return 0;
-
-       orignode = msg_orignode(msg);
-       peernode = tipc_port_peernode(p_ptr);
-       return (orignode == peernode) ||
-               (!orignode && (peernode == tipc_own_addr)) ||
-               (!peernode && (orignode == tipc_own_addr));
-}
-
-/* tipc_port_init - intiate TIPC port and lock it
- *
- * Returns obtained reference if initialization is successful, zero otherwise
- */
-u32 tipc_port_init(struct tipc_port *p_ptr,
-                  const unsigned int importance)
-{
-       struct tipc_msg *msg;
-       u32 ref;
-
-       ref = tipc_ref_acquire(p_ptr, &p_ptr->lock);
-       if (!ref) {
-               pr_warn("Port registration failed, ref. table exhausted\n");
-               return 0;
-       }
-
-       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);
-       k_init_timer(&p_ptr->timer, (Handler)port_timeout, ref);
-       INIT_LIST_HEAD(&p_ptr->publications);
-       INIT_LIST_HEAD(&p_ptr->port_list);
-
-       /*
-        * Must hold port list lock while initializing message header template
-        * to ensure a change to node's own network address doesn't result
-        * in template containing out-dated network address information
-        */
-       spin_lock_bh(&tipc_port_list_lock);
-       msg = &p_ptr->phdr;
-       tipc_msg_init(msg, importance, TIPC_NAMED_MSG, NAMED_H_SIZE, 0);
-       msg_set_origport(msg, ref);
-       list_add_tail(&p_ptr->port_list, &ports);
-       spin_unlock_bh(&tipc_port_list_lock);
-       return ref;
-}
-
-void tipc_port_destroy(struct tipc_port *p_ptr)
-{
-       struct sk_buff *buf = NULL;
-       struct tipc_msg *msg = NULL;
-       u32 peer;
-
-       tipc_withdraw(p_ptr, 0, NULL);
-
-       spin_lock_bh(p_ptr->lock);
-       tipc_ref_discard(p_ptr->ref);
-       spin_unlock_bh(p_ptr->lock);
-
-       k_cancel_timer(&p_ptr->timer);
-       if (p_ptr->connected) {
-               buf = port_build_peer_abort_msg(p_ptr, TIPC_ERR_NO_PORT);
-               tipc_nodesub_unsubscribe(&p_ptr->subscription);
-               msg = buf_msg(buf);
-               peer = msg_destnode(msg);
-               tipc_link_xmit(buf, peer, msg_link_selector(msg));
-       }
-       spin_lock_bh(&tipc_port_list_lock);
-       list_del(&p_ptr->port_list);
-       list_del(&p_ptr->wait_list);
-       spin_unlock_bh(&tipc_port_list_lock);
-       k_term_timer(&p_ptr->timer);
-}
-
-/*
- * port_build_proto_msg(): create connection protocol message for port
- *
- * On entry the port must be locked and connected.
- */
-static struct sk_buff *port_build_proto_msg(struct tipc_port *p_ptr,
-                                           u32 type, u32 ack)
-{
-       struct sk_buff *buf;
-       struct tipc_msg *msg;
-
-       buf = tipc_buf_acquire(INT_H_SIZE);
-       if (buf) {
-               msg = buf_msg(buf);
-               tipc_msg_init(msg, CONN_MANAGER, type, INT_H_SIZE,
-                             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);
-               buf->next = NULL;
-       }
-       return buf;
-}
-
-static void port_timeout(unsigned long ref)
-{
-       struct tipc_port *p_ptr = tipc_port_lock(ref);
-       struct sk_buff *buf = NULL;
-       struct tipc_msg *msg = NULL;
-
-       if (!p_ptr)
-               return;
-
-       if (!p_ptr->connected) {
-               tipc_port_unlock(p_ptr);
-               return;
-       }
-
-       /* Last probe answered ? */
-       if (p_ptr->probing_state == TIPC_CONN_PROBING) {
-               buf = port_build_self_abort_msg(p_ptr, TIPC_ERR_NO_PORT);
-       } else {
-               buf = port_build_proto_msg(p_ptr, CONN_PROBE, 0);
-               p_ptr->probing_state = TIPC_CONN_PROBING;
-               k_start_timer(&p_ptr->timer, p_ptr->probing_interval);
-       }
-       tipc_port_unlock(p_ptr);
-       msg = buf_msg(buf);
-       tipc_link_xmit(buf, msg_destnode(msg),  msg_link_selector(msg));
-}
-
-
-static void port_handle_node_down(unsigned long ref)
-{
-       struct tipc_port *p_ptr = tipc_port_lock(ref);
-       struct sk_buff *buf = NULL;
-       struct tipc_msg *msg = NULL;
-
-       if (!p_ptr)
-               return;
-       buf = port_build_self_abort_msg(p_ptr, TIPC_ERR_NO_NODE);
-       tipc_port_unlock(p_ptr);
-       msg = buf_msg(buf);
-       tipc_link_xmit(buf, msg_destnode(msg),  msg_link_selector(msg));
-}
-
-
-static struct sk_buff *port_build_self_abort_msg(struct tipc_port *p_ptr, u32 err)
-{
-       struct sk_buff *buf = port_build_peer_abort_msg(p_ptr, err);
-
-       if (buf) {
-               struct tipc_msg *msg = buf_msg(buf);
-               msg_swap_words(msg, 4, 5);
-               msg_swap_words(msg, 6, 7);
-               buf->next = NULL;
-       }
-       return buf;
-}
-
-
-static struct sk_buff *port_build_peer_abort_msg(struct tipc_port *p_ptr, u32 err)
-{
-       struct sk_buff *buf;
-       struct tipc_msg *msg;
-       u32 imp;
-
-       if (!p_ptr->connected)
-               return NULL;
-
-       buf = tipc_buf_acquire(BASIC_H_SIZE);
-       if (buf) {
-               msg = buf_msg(buf);
-               memcpy(msg, &p_ptr->phdr, BASIC_H_SIZE);
-               msg_set_hdr_sz(msg, BASIC_H_SIZE);
-               msg_set_size(msg, BASIC_H_SIZE);
-               imp = msg_importance(msg);
-               if (imp < TIPC_CRITICAL_IMPORTANCE)
-                       msg_set_importance(msg, ++imp);
-               msg_set_errcode(msg, err);
-               buf->next = NULL;
-       }
-       return buf;
-}
-
-static int port_print(struct tipc_port *p_ptr, char *buf, int len, int full_id)
-{
-       struct publication *publ;
-       int ret;
-
-       if (full_id)
-               ret = tipc_snprintf(buf, len, "<%u.%u.%u:%u>:",
-                                   tipc_zone(tipc_own_addr),
-                                   tipc_cluster(tipc_own_addr),
-                                   tipc_node(tipc_own_addr), p_ptr->ref);
-       else
-               ret = tipc_snprintf(buf, len, "%-10u:", p_ptr->ref);
-
-       if (p_ptr->connected) {
-               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>",
-                                    tipc_zone(destnode),
-                                    tipc_cluster(destnode),
-                                    tipc_node(destnode), dport);
-               if (p_ptr->conn_type != 0)
-                       ret += tipc_snprintf(buf + ret, len - ret,
-                                            " via {%u,%u}", p_ptr->conn_type,
-                                            p_ptr->conn_instance);
-       } else if (p_ptr->published) {
-               ret += tipc_snprintf(buf + ret, len - ret, " bound to");
-               list_for_each_entry(publ, &p_ptr->publications, pport_list) {
-                       if (publ->lower == publ->upper)
-                               ret += tipc_snprintf(buf + ret, len - ret,
-                                                    " {%u,%u}", publ->type,
-                                                    publ->lower);
-                       else
-                               ret += tipc_snprintf(buf + ret, len - ret,
-                                                    " {%u,%u,%u}", publ->type,
-                                                    publ->lower, publ->upper);
-               }
-       }
-       ret += tipc_snprintf(buf + ret, len - ret, "\n");
-       return ret;
-}
-
-struct sk_buff *tipc_port_get_ports(void)
-{
-       struct sk_buff *buf;
-       struct tlv_desc *rep_tlv;
-       char *pb;
-       int pb_len;
-       struct tipc_port *p_ptr;
-       int str_len = 0;
-
-       buf = tipc_cfg_reply_alloc(TLV_SPACE(ULTRA_STRING_MAX_LEN));
-       if (!buf)
-               return NULL;
-       rep_tlv = (struct tlv_desc *)buf->data;
-       pb = TLV_DATA(rep_tlv);
-       pb_len = ULTRA_STRING_MAX_LEN;
-
-       spin_lock_bh(&tipc_port_list_lock);
-       list_for_each_entry(p_ptr, &ports, port_list) {
-               spin_lock_bh(p_ptr->lock);
-               str_len += port_print(p_ptr, pb, pb_len, 0);
-               spin_unlock_bh(p_ptr->lock);
-       }
-       spin_unlock_bh(&tipc_port_list_lock);
-       str_len += 1;   /* for "\0" */
-       skb_put(buf, TLV_SPACE(str_len));
-       TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
-
-       return buf;
-}
-
-void tipc_port_reinit(void)
-{
-       struct tipc_port *p_ptr;
-       struct tipc_msg *msg;
-
-       spin_lock_bh(&tipc_port_list_lock);
-       list_for_each_entry(p_ptr, &ports, port_list) {
-               msg = &p_ptr->phdr;
-               msg_set_prevnode(msg, tipc_own_addr);
-               msg_set_orignode(msg, tipc_own_addr);
-       }
-       spin_unlock_bh(&tipc_port_list_lock);
-}
-
-void tipc_acknowledge(u32 ref, u32 ack)
-{
-       struct tipc_port *p_ptr;
-       struct sk_buff *buf = NULL;
-       struct tipc_msg *msg;
-
-       p_ptr = tipc_port_lock(ref);
-       if (!p_ptr)
-               return;
-       if (p_ptr->connected)
-               buf = port_build_proto_msg(p_ptr, CONN_ACK, ack);
-
-       tipc_port_unlock(p_ptr);
-       if (!buf)
-               return;
-       msg = buf_msg(buf);
-       tipc_link_xmit(buf, msg_destnode(msg),  msg_link_selector(msg));
-}
-
-int tipc_publish(struct tipc_port *p_ptr, unsigned int scope,
-                struct tipc_name_seq const *seq)
-{
-       struct publication *publ;
-       u32 key;
-
-       if (p_ptr->connected)
-               return -EINVAL;
-       key = p_ptr->ref + p_ptr->pub_count + 1;
-       if (key == p_ptr->ref)
-               return -EADDRINUSE;
-
-       publ = tipc_nametbl_publish(seq->type, seq->lower, seq->upper,
-                                   scope, p_ptr->ref, key);
-       if (publ) {
-               list_add(&publ->pport_list, &p_ptr->publications);
-               p_ptr->pub_count++;
-               p_ptr->published = 1;
-               return 0;
-       }
-       return -EINVAL;
-}
-
-int tipc_withdraw(struct tipc_port *p_ptr, unsigned int scope,
-                 struct tipc_name_seq const *seq)
-{
-       struct publication *publ;
-       struct publication *tpubl;
-       int res = -EINVAL;
-
-       if (!seq) {
-               list_for_each_entry_safe(publ, tpubl,
-                                        &p_ptr->publications, pport_list) {
-                       tipc_nametbl_withdraw(publ->type, publ->lower,
-                                             publ->ref, publ->key);
-               }
-               res = 0;
-       } else {
-               list_for_each_entry_safe(publ, tpubl,
-                                        &p_ptr->publications, pport_list) {
-                       if (publ->scope != scope)
-                               continue;
-                       if (publ->type != seq->type)
-                               continue;
-                       if (publ->lower != seq->lower)
-                               continue;
-                       if (publ->upper != seq->upper)
-                               break;
-                       tipc_nametbl_withdraw(publ->type, publ->lower,
-                                             publ->ref, publ->key);
-                       res = 0;
-                       break;
-               }
-       }
-       if (list_empty(&p_ptr->publications))
-               p_ptr->published = 0;
-       return res;
-}
-
-int tipc_port_connect(u32 ref, struct tipc_portid const *peer)
-{
-       struct tipc_port *p_ptr;
-       int res;
-
-       p_ptr = tipc_port_lock(ref);
-       if (!p_ptr)
-               return -EINVAL;
-       res = __tipc_port_connect(ref, p_ptr, peer);
-       tipc_port_unlock(p_ptr);
-       return res;
-}
-
-/*
- * __tipc_port_connect - connect to a remote peer
- *
- * Port must be locked.
- */
-int __tipc_port_connect(u32 ref, struct tipc_port *p_ptr,
-                       struct tipc_portid const *peer)
-{
-       struct tipc_msg *msg;
-       int res = -EINVAL;
-
-       if (p_ptr->published || p_ptr->connected)
-               goto exit;
-       if (!peer->ref)
-               goto exit;
-
-       msg = &p_ptr->phdr;
-       msg_set_destnode(msg, peer->node);
-       msg_set_destport(msg, peer->ref);
-       msg_set_type(msg, TIPC_CONN_MSG);
-       msg_set_lookup_scope(msg, 0);
-       msg_set_hdr_sz(msg, SHORT_H_SIZE);
-
-       p_ptr->probing_interval = PROBING_INTERVAL;
-       p_ptr->probing_state = TIPC_CONN_OK;
-       p_ptr->connected = 1;
-       k_start_timer(&p_ptr->timer, p_ptr->probing_interval);
-
-       tipc_nodesub_subscribe(&p_ptr->subscription, peer->node,
-                         (void *)(unsigned long)ref,
-                         (net_ev_handler)port_handle_node_down);
-       res = 0;
-exit:
-       p_ptr->max_pkt = tipc_node_get_mtu(peer->node, ref);
-       return res;
-}
-
-/*
- * __tipc_disconnect - disconnect port from peer
- *
- * Port must be locked.
- */
-int __tipc_port_disconnect(struct tipc_port *tp_ptr)
-{
-       if (tp_ptr->connected) {
-               tp_ptr->connected = 0;
-               /* let timer expire on it's own to avoid deadlock! */
-               tipc_nodesub_unsubscribe(&tp_ptr->subscription);
-               return 0;
-       }
-
-       return -ENOTCONN;
-}
-
-/*
- * tipc_port_disconnect(): Disconnect port form peer.
- *                    This is a node local operation.
- */
-int tipc_port_disconnect(u32 ref)
-{
-       struct tipc_port *p_ptr;
-       int res;
-
-       p_ptr = tipc_port_lock(ref);
-       if (!p_ptr)
-               return -EINVAL;
-       res = __tipc_port_disconnect(p_ptr);
-       tipc_port_unlock(p_ptr);
-       return res;
-}
-
-/*
- * tipc_port_shutdown(): Send a SHUTDOWN msg to peer and disconnect
- */
-int tipc_port_shutdown(u32 ref)
-{
-       struct tipc_msg *msg;
-       struct tipc_port *p_ptr;
-       struct sk_buff *buf = NULL;
-
-       p_ptr = tipc_port_lock(ref);
-       if (!p_ptr)
-               return -EINVAL;
-
-       buf = port_build_peer_abort_msg(p_ptr, TIPC_CONN_SHUTDOWN);
-       tipc_port_unlock(p_ptr);
-       msg = buf_msg(buf);
-       tipc_link_xmit(buf, msg_destnode(msg),  msg_link_selector(msg));
-       return tipc_port_disconnect(ref);
-}
diff --git a/net/tipc/port.h b/net/tipc/port.h
deleted file mode 100644 (file)
index 3f93454..0000000
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * net/tipc/port.h: Include file for TIPC port code
- *
- * Copyright (c) 1994-2007, 2014, Ericsson AB
- * Copyright (c) 2004-2007, 2010-2013, Wind River Systems
- * 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_PORT_H
-#define _TIPC_PORT_H
-
-#include "ref.h"
-#include "net.h"
-#include "msg.h"
-#include "node_subscr.h"
-
-#define TIPC_CONNACK_INTV         256
-#define TIPC_FLOWCTRL_WIN        (TIPC_CONNACK_INTV * 2)
-#define TIPC_CONN_OVERLOAD_LIMIT ((TIPC_FLOWCTRL_WIN * 2 + 1) * \
-                                 SKB_TRUESIZE(TIPC_MAX_USER_MSG_SIZE))
-
-/**
- * struct tipc_port - TIPC port structure
- * @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
- * @conn_instance: TIPC instance used when connection was established
- * @published: non-zero if port has one or more associated names
- * @max_pkt: maximum packet size "hint" used when building messages sent by port
- * @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
- * @wait_list: adjacent ports in list of ports waiting on link congestion
- * @waiting_pkts:
- * @publications: list of publications for port
- * @pub_count: total # of publications port has made during its lifetime
- * @probing_state:
- * @probing_interval:
- * @timer_ref:
- * @subscription: "node down" subscription used to terminate failed connections
- */
-struct tipc_port {
-       spinlock_t *lock;
-       int connected;
-       u32 conn_type;
-       u32 conn_instance;
-       int published;
-       u32 max_pkt;
-       u32 ref;
-       struct tipc_msg phdr;
-       struct list_head port_list;
-       struct list_head wait_list;
-       u32 waiting_pkts;
-       struct list_head publications;
-       u32 pub_count;
-       u32 probing_state;
-       u32 probing_interval;
-       struct timer_list timer;
-       struct tipc_node_subscr subscription;
-};
-
-extern spinlock_t tipc_port_list_lock;
-struct tipc_port_list;
-
-/*
- * TIPC port manipulation routines
- */
-u32 tipc_port_init(struct tipc_port *p_ptr,
-                  const unsigned int importance);
-
-void tipc_acknowledge(u32 port_ref, u32 ack);
-
-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_port_connect(u32 portref, struct tipc_portid const *port);
-
-int tipc_port_disconnect(u32 portref);
-
-int tipc_port_shutdown(u32 ref);
-
-/*
- * The following routines require that the port be locked on entry
- */
-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);
-
-struct sk_buff *tipc_port_get_ports(void);
-void tipc_port_reinit(void);
-
-/**
- * tipc_port_lock - lock port instance referred to and return its pointer
- */
-static inline struct tipc_port *tipc_port_lock(u32 ref)
-{
-       return (struct tipc_port *)tipc_ref_lock(ref);
-}
-
-/**
- * tipc_port_unlock - unlock a port instance
- *
- * Can use pointer instead of tipc_ref_unlock() since port is already locked.
- */
-static inline void tipc_port_unlock(struct tipc_port *p_ptr)
-{
-       spin_unlock_bh(p_ptr->lock);
-}
-
-static inline u32 tipc_port_peernode(struct tipc_port *p_ptr)
-{
-       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
diff --git a/net/tipc/ref.c b/net/tipc/ref.c
deleted file mode 100644 (file)
index 3d4ecd7..0000000
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * net/tipc/ref.c: TIPC object registry code
- *
- * Copyright (c) 1991-2006, Ericsson AB
- * Copyright (c) 2004-2007, Wind River Systems
- * 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.
- */
-
-#include "core.h"
-#include "ref.h"
-
-/**
- * struct reference - TIPC object reference entry
- * @object: pointer to object associated with reference entry
- * @lock: spinlock controlling access to object
- * @ref: reference value for object (combines instance & array index info)
- */
-struct reference {
-       void *object;
-       spinlock_t lock;
-       u32 ref;
-};
-
-/**
- * struct tipc_ref_table - table of TIPC object reference entries
- * @entries: pointer to array of reference entries
- * @capacity: array index of first unusable entry
- * @init_point: array index of first uninitialized entry
- * @first_free: array index of first unused object reference entry
- * @last_free: array index of last unused object reference entry
- * @index_mask: bitmask for array index portion of reference values
- * @start_mask: initial value for instance value portion of reference values
- */
-struct ref_table {
-       struct reference *entries;
-       u32 capacity;
-       u32 init_point;
-       u32 first_free;
-       u32 last_free;
-       u32 index_mask;
-       u32 start_mask;
-};
-
-/*
- * Object reference table consists of 2**N entries.
- *
- * State       Object ptr      Reference
- * -----        ----------      ---------
- * In use        non-NULL       XXXX|own index
- *                             (XXXX changes each time entry is acquired)
- * Free            NULL         YYYY|next free index
- *                             (YYYY is one more than last used XXXX)
- * Uninitialized   NULL         0
- *
- * Entry 0 is not used; this allows index 0 to denote the end of the free list.
- *
- * Note that a reference value of 0 does not necessarily indicate that an
- * entry is uninitialized, since the last entry in the free list could also
- * have a reference value of 0 (although this is unlikely).
- */
-
-static struct ref_table tipc_ref_table;
-
-static DEFINE_SPINLOCK(ref_table_lock);
-
-/**
- * tipc_ref_table_init - create reference table for objects
- */
-int tipc_ref_table_init(u32 requested_size, u32 start)
-{
-       struct reference *table;
-       u32 actual_size;
-
-       /* account for unused entry, then round up size to a power of 2 */
-
-       requested_size++;
-       for (actual_size = 16; actual_size < requested_size; actual_size <<= 1)
-               /* do nothing */ ;
-
-       /* allocate table & mark all entries as uninitialized */
-       table = vzalloc(actual_size * sizeof(struct reference));
-       if (table == NULL)
-               return -ENOMEM;
-
-       tipc_ref_table.entries = table;
-       tipc_ref_table.capacity = requested_size;
-       tipc_ref_table.init_point = 1;
-       tipc_ref_table.first_free = 0;
-       tipc_ref_table.last_free = 0;
-       tipc_ref_table.index_mask = actual_size - 1;
-       tipc_ref_table.start_mask = start & ~tipc_ref_table.index_mask;
-
-       return 0;
-}
-
-/**
- * tipc_ref_table_stop - destroy reference table for objects
- */
-void tipc_ref_table_stop(void)
-{
-       vfree(tipc_ref_table.entries);
-       tipc_ref_table.entries = NULL;
-}
-
-/**
- * tipc_ref_acquire - create reference to an object
- *
- * Register an object pointer in reference table and lock the object.
- * Returns a unique reference value that is used from then on to retrieve the
- * object pointer, or to determine that the object has been deregistered.
- *
- * Note: The object is returned in the locked state so that the caller can
- * register a partially initialized object, without running the risk that
- * the object will be accessed before initialization is complete.
- */
-u32 tipc_ref_acquire(void *object, spinlock_t **lock)
-{
-       u32 index;
-       u32 index_mask;
-       u32 next_plus_upper;
-       u32 ref;
-       struct reference *entry = NULL;
-
-       if (!object) {
-               pr_err("Attempt to acquire ref. to non-existent obj\n");
-               return 0;
-       }
-       if (!tipc_ref_table.entries) {
-               pr_err("Ref. table not found in acquisition attempt\n");
-               return 0;
-       }
-
-       /* take a free entry, if available; otherwise initialize a new entry */
-       spin_lock_bh(&ref_table_lock);
-       if (tipc_ref_table.first_free) {
-               index = tipc_ref_table.first_free;
-               entry = &(tipc_ref_table.entries[index]);
-               index_mask = tipc_ref_table.index_mask;
-               next_plus_upper = entry->ref;
-               tipc_ref_table.first_free = next_plus_upper & index_mask;
-               ref = (next_plus_upper & ~index_mask) + index;
-       } else if (tipc_ref_table.init_point < tipc_ref_table.capacity) {
-               index = tipc_ref_table.init_point++;
-               entry = &(tipc_ref_table.entries[index]);
-               spin_lock_init(&entry->lock);
-               ref = tipc_ref_table.start_mask + index;
-       } else {
-               ref = 0;
-       }
-       spin_unlock_bh(&ref_table_lock);
-
-       /*
-        * Grab the lock so no one else can modify this entry
-        * While we assign its ref value & object pointer
-        */
-       if (entry) {
-               spin_lock_bh(&entry->lock);
-               entry->ref = ref;
-               entry->object = object;
-               *lock = &entry->lock;
-               /*
-                * keep it locked, the caller is responsible
-                * for unlocking this when they're done with it
-                */
-       }
-
-       return ref;
-}
-
-/**
- * tipc_ref_discard - invalidate references to an object
- *
- * Disallow future references to an object and free up the entry for re-use.
- * Note: The entry's spin_lock may still be busy after discard
- */
-void tipc_ref_discard(u32 ref)
-{
-       struct reference *entry;
-       u32 index;
-       u32 index_mask;
-
-       if (!tipc_ref_table.entries) {
-               pr_err("Ref. table not found during discard attempt\n");
-               return;
-       }
-
-       index_mask = tipc_ref_table.index_mask;
-       index = ref & index_mask;
-       entry = &(tipc_ref_table.entries[index]);
-
-       spin_lock_bh(&ref_table_lock);
-
-       if (!entry->object) {
-               pr_err("Attempt to discard ref. to non-existent obj\n");
-               goto exit;
-       }
-       if (entry->ref != ref) {
-               pr_err("Attempt to discard non-existent reference\n");
-               goto exit;
-       }
-
-       /*
-        * mark entry as unused; increment instance part of entry's reference
-        * to invalidate any subsequent references
-        */
-       entry->object = NULL;
-       entry->ref = (ref & ~index_mask) + (index_mask + 1);
-
-       /* append entry to free entry list */
-       if (tipc_ref_table.first_free == 0)
-               tipc_ref_table.first_free = index;
-       else
-               tipc_ref_table.entries[tipc_ref_table.last_free].ref |= index;
-       tipc_ref_table.last_free = index;
-
-exit:
-       spin_unlock_bh(&ref_table_lock);
-}
-
-/**
- * tipc_ref_lock - lock referenced object and return pointer to it
- */
-void *tipc_ref_lock(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 != 0)) {
-                       spin_lock_bh(&entry->lock);
-                       if (likely((entry->ref == ref) && (entry->object)))
-                               return entry->object;
-                       spin_unlock_bh(&entry->lock);
-               }
-       }
-       return NULL;
-}
diff --git a/net/tipc/ref.h b/net/tipc/ref.h
deleted file mode 100644 (file)
index d01aa1d..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * net/tipc/ref.h: Include file for TIPC object registry code
- *
- * Copyright (c) 1991-2006, Ericsson AB
- * Copyright (c) 2005-2006, Wind River Systems
- * 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_REF_H
-#define _TIPC_REF_H
-
-int tipc_ref_table_init(u32 requested_size, u32 start);
-void tipc_ref_table_stop(void);
-
-u32 tipc_ref_acquire(void *object, spinlock_t **lock);
-void tipc_ref_discard(u32 ref);
-
-void *tipc_ref_lock(u32 ref);
-
-#endif
index 7d423ee10897ca6978cb3030cdaae6f0c81814a1..75275c5cf9291a0afe0818b6ef99ccfc14db8822 100644 (file)
  */
 
 #include "core.h"
-#include "port.h"
 #include "name_table.h"
 #include "node.h"
 #include "link.h"
 #include <linux/export.h>
+#include "config.h"
+#include "socket.h"
 
 #define SS_LISTENING   -1      /* socket is listening */
 #define SS_READY       -2      /* socket is connectionless */
 
-#define CONN_TIMEOUT_DEFAULT   8000    /* default connect timeout = 8s */
-#define TIPC_FWD_MSG           1
+#define CONN_TIMEOUT_DEFAULT  8000     /* default connect timeout = 8s */
+#define CONN_PROBING_INTERVAL 3600000  /* [ms] => 1 h */
+#define TIPC_FWD_MSG         1
+#define TIPC_CONN_OK          0
+#define TIPC_CONN_PROBING     1
+
+/**
+ * struct tipc_sock - TIPC socket structure
+ * @sk: socket - interacts with 'port' and with user via the socket API
+ * @connected: non-zero if port is currently connected to a peer port
+ * @conn_type: TIPC type used when connection was established
+ * @conn_instance: TIPC instance used when connection was established
+ * @published: non-zero if port has one or more associated names
+ * @max_pkt: maximum packet size "hint" used when building messages sent by port
+ * @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
+ * @publications: list of publications for port
+ * @pub_count: total # of publications port has made during its lifetime
+ * @probing_state:
+ * @probing_interval:
+ * @timer:
+ * @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
+ * @dupl_rcvcnt: number of bytes counted twice, in both backlog and rcv queue
+ * @link_cong: non-zero if owner must sleep because of link congestion
+ * @sent_unacked: # messages sent by socket, and not yet acked by peer
+ * @rcv_unacked: # messages read by user, but not yet acked back to peer
+ */
+struct tipc_sock {
+       struct sock sk;
+       int connected;
+       u32 conn_type;
+       u32 conn_instance;
+       int published;
+       u32 max_pkt;
+       u32 ref;
+       struct tipc_msg phdr;
+       struct list_head sock_list;
+       struct list_head publications;
+       u32 pub_count;
+       u32 probing_state;
+       u32 probing_interval;
+       struct timer_list timer;
+       uint conn_timeout;
+       atomic_t dupl_rcvcnt;
+       bool link_cong;
+       uint sent_unacked;
+       uint rcv_unacked;
+};
 
 static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *skb);
 static void tipc_data_ready(struct sock *sk);
@@ -53,6 +103,16 @@ static void tipc_write_space(struct sock *sk);
 static int tipc_release(struct socket *sock);
 static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags);
 static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p);
+static void tipc_sk_timeout(unsigned long ref);
+static int tipc_sk_publish(struct tipc_sock *tsk, uint scope,
+                          struct tipc_name_seq const *seq);
+static int tipc_sk_withdraw(struct tipc_sock *tsk, uint scope,
+                           struct tipc_name_seq const *seq);
+static u32 tipc_sk_ref_acquire(struct tipc_sock *tsk);
+static void tipc_sk_ref_discard(u32 ref);
+static struct tipc_sock *tipc_sk_get(u32 ref);
+static struct tipc_sock *tipc_sk_get_next(u32 *ref);
+static void tipc_sk_put(struct tipc_sock *tsk);
 
 static const struct proto_ops packet_ops;
 static const struct proto_ops stream_ops;
@@ -106,24 +166,75 @@ static struct proto tipc_proto_kern;
  *   - port reference
  */
 
-#include "socket.h"
+static u32 tsk_peer_node(struct tipc_sock *tsk)
+{
+       return msg_destnode(&tsk->phdr);
+}
+
+static u32 tsk_peer_port(struct tipc_sock *tsk)
+{
+       return msg_destport(&tsk->phdr);
+}
+
+static  bool tsk_unreliable(struct tipc_sock *tsk)
+{
+       return msg_src_droppable(&tsk->phdr) != 0;
+}
+
+static void tsk_set_unreliable(struct tipc_sock *tsk, bool unreliable)
+{
+       msg_set_src_droppable(&tsk->phdr, unreliable ? 1 : 0);
+}
+
+static bool tsk_unreturnable(struct tipc_sock *tsk)
+{
+       return msg_dest_droppable(&tsk->phdr) != 0;
+}
+
+static void tsk_set_unreturnable(struct tipc_sock *tsk, bool unreturnable)
+{
+       msg_set_dest_droppable(&tsk->phdr, unreturnable ? 1 : 0);
+}
+
+static int tsk_importance(struct tipc_sock *tsk)
+{
+       return msg_importance(&tsk->phdr);
+}
+
+static int tsk_set_importance(struct tipc_sock *tsk, int imp)
+{
+       if (imp > TIPC_CRITICAL_IMPORTANCE)
+               return -EINVAL;
+       msg_set_importance(&tsk->phdr, (u32)imp);
+       return 0;
+}
+
+static struct tipc_sock *tipc_sk(const struct sock *sk)
+{
+       return container_of(sk, struct tipc_sock, sk);
+}
+
+static int tsk_conn_cong(struct tipc_sock *tsk)
+{
+       return tsk->sent_unacked >= TIPC_FLOWCTRL_WIN;
+}
 
 /**
- * advance_rx_queue - discard first buffer in socket receive queue
+ * tsk_advance_rx_queue - discard first buffer in socket receive queue
  *
  * Caller must hold socket lock
  */
-static void advance_rx_queue(struct sock *sk)
+static void tsk_advance_rx_queue(struct sock *sk)
 {
        kfree_skb(__skb_dequeue(&sk->sk_receive_queue));
 }
 
 /**
- * reject_rx_queue - reject all buffers in socket receive queue
+ * tsk_rej_rx_queue - reject all buffers in socket receive queue
  *
  * Caller must hold socket lock
  */
-static void reject_rx_queue(struct sock *sk)
+static void tsk_rej_rx_queue(struct sock *sk)
 {
        struct sk_buff *buf;
        u32 dnode;
@@ -134,6 +245,38 @@ static void reject_rx_queue(struct sock *sk)
        }
 }
 
+/* tsk_peer_msg - verify if message was sent by connected port's peer
+ *
+ * Handles cases where the node's network address has changed from
+ * the default of <0.0.0> to its configured setting.
+ */
+static bool tsk_peer_msg(struct tipc_sock *tsk, struct tipc_msg *msg)
+{
+       u32 peer_port = tsk_peer_port(tsk);
+       u32 orig_node;
+       u32 peer_node;
+
+       if (unlikely(!tsk->connected))
+               return false;
+
+       if (unlikely(msg_origport(msg) != peer_port))
+               return false;
+
+       orig_node = msg_orignode(msg);
+       peer_node = tsk_peer_node(tsk);
+
+       if (likely(orig_node == peer_node))
+               return true;
+
+       if (!orig_node && (peer_node == tipc_own_addr))
+               return true;
+
+       if (!peer_node && (orig_node == tipc_own_addr))
+               return true;
+
+       return false;
+}
+
 /**
  * tipc_sk_create - create a TIPC socket
  * @net: network namespace (must be default network)
@@ -153,7 +296,7 @@ static int tipc_sk_create(struct net *net, struct socket *sock,
        socket_state state;
        struct sock *sk;
        struct tipc_sock *tsk;
-       struct tipc_port *port;
+       struct tipc_msg *msg;
        u32 ref;
 
        /* Validate arguments */
@@ -188,20 +331,24 @@ static int tipc_sk_create(struct net *net, struct socket *sock,
                return -ENOMEM;
 
        tsk = tipc_sk(sk);
-       port = &tsk->port;
-
-       ref = tipc_port_init(port, TIPC_LOW_IMPORTANCE);
+       ref = tipc_sk_ref_acquire(tsk);
        if (!ref) {
-               pr_warn("Socket registration failed, ref. table exhausted\n");
-               sk_free(sk);
+               pr_warn("Socket create failed; reference table exhausted\n");
                return -ENOMEM;
        }
+       tsk->max_pkt = MAX_PKT_DEFAULT;
+       tsk->ref = ref;
+       INIT_LIST_HEAD(&tsk->publications);
+       msg = &tsk->phdr;
+       tipc_msg_init(msg, TIPC_LOW_IMPORTANCE, TIPC_NAMED_MSG,
+                     NAMED_H_SIZE, 0);
+       msg_set_origport(msg, ref);
 
        /* Finish initializing socket data structures */
        sock->ops = ops;
        sock->state = state;
-
        sock_init_data(sock, sk);
+       k_init_timer(&tsk->timer, (Handler)tipc_sk_timeout, ref);
        sk->sk_backlog_rcv = tipc_backlog_rcv;
        sk->sk_rcvbuf = sysctl_tipc_rmem[1];
        sk->sk_data_ready = tipc_data_ready;
@@ -209,12 +356,11 @@ static int tipc_sk_create(struct net *net, struct socket *sock,
        tsk->conn_timeout = CONN_TIMEOUT_DEFAULT;
        tsk->sent_unacked = 0;
        atomic_set(&tsk->dupl_rcvcnt, 0);
-       tipc_port_unlock(port);
 
        if (sock->state == SS_READY) {
-               tipc_port_set_unreturnable(port, true);
+               tsk_set_unreturnable(tsk, true);
                if (sock->type == SOCK_DGRAM)
-                       tipc_port_set_unreliable(port, true);
+                       tsk_set_unreliable(tsk, true);
        }
        return 0;
 }
@@ -308,7 +454,6 @@ static int tipc_release(struct socket *sock)
 {
        struct sock *sk = sock->sk;
        struct tipc_sock *tsk;
-       struct tipc_port *port;
        struct sk_buff *buf;
        u32 dnode;
 
@@ -320,13 +465,13 @@ static int tipc_release(struct socket *sock)
                return 0;
 
        tsk = tipc_sk(sk);
-       port = &tsk->port;
        lock_sock(sk);
 
        /*
         * Reject all unreceived messages, except on an active connection
         * (which disconnects locally & sends a 'FIN+' to peer)
         */
+       dnode = tsk_peer_node(tsk);
        while (sock->state != SS_DISCONNECTING) {
                buf = __skb_dequeue(&sk->sk_receive_queue);
                if (buf == NULL)
@@ -337,17 +482,27 @@ static int tipc_release(struct socket *sock)
                        if ((sock->state == SS_CONNECTING) ||
                            (sock->state == SS_CONNECTED)) {
                                sock->state = SS_DISCONNECTING;
-                               tipc_port_disconnect(port->ref);
+                               tsk->connected = 0;
+                               tipc_node_remove_conn(dnode, tsk->ref);
                        }
                        if (tipc_msg_reverse(buf, &dnode, TIPC_ERR_NO_PORT))
                                tipc_link_xmit(buf, dnode, 0);
                }
        }
 
-       /* Destroy TIPC port; also disconnects an active connection and
-        * sends a 'FIN-' to peer.
-        */
-       tipc_port_destroy(port);
+       tipc_sk_withdraw(tsk, 0, NULL);
+       tipc_sk_ref_discard(tsk->ref);
+       k_cancel_timer(&tsk->timer);
+       if (tsk->connected) {
+               buf = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE, TIPC_CONN_MSG,
+                                     SHORT_H_SIZE, 0, dnode, tipc_own_addr,
+                                     tsk_peer_port(tsk),
+                                     tsk->ref, TIPC_ERR_NO_PORT);
+               if (buf)
+                       tipc_link_xmit(buf, dnode, tsk->ref);
+               tipc_node_remove_conn(dnode, tsk->ref);
+       }
+       k_term_timer(&tsk->timer);
 
        /* Discard any remaining (connection-based) messages in receive queue */
        __skb_queue_purge(&sk->sk_receive_queue);
@@ -355,7 +510,6 @@ static int tipc_release(struct socket *sock)
        /* Reject any messages that accumulated in backlog queue */
        sock->state = SS_DISCONNECTING;
        release_sock(sk);
-
        sock_put(sk);
        sock->sk = NULL;
 
@@ -387,7 +541,7 @@ static int tipc_bind(struct socket *sock, struct sockaddr *uaddr,
 
        lock_sock(sk);
        if (unlikely(!uaddr_len)) {
-               res = tipc_withdraw(&tsk->port, 0, NULL);
+               res = tipc_sk_withdraw(tsk, 0, NULL);
                goto exit;
        }
 
@@ -415,8 +569,8 @@ static int tipc_bind(struct socket *sock, struct sockaddr *uaddr,
        }
 
        res = (addr->scope > 0) ?
-               tipc_publish(&tsk->port, addr->scope, &addr->addr.nameseq) :
-               tipc_withdraw(&tsk->port, -addr->scope, &addr->addr.nameseq);
+               tipc_sk_publish(tsk, addr->scope, &addr->addr.nameseq) :
+               tipc_sk_withdraw(tsk, -addr->scope, &addr->addr.nameseq);
 exit:
        release_sock(sk);
        return res;
@@ -446,10 +600,10 @@ static int tipc_getname(struct socket *sock, struct sockaddr *uaddr,
                if ((sock->state != SS_CONNECTED) &&
                        ((peer != 2) || (sock->state != SS_DISCONNECTING)))
                        return -ENOTCONN;
-               addr->addr.id.ref = tipc_port_peerport(&tsk->port);
-               addr->addr.id.node = tipc_port_peernode(&tsk->port);
+               addr->addr.id.ref = tsk_peer_port(tsk);
+               addr->addr.id.node = tsk_peer_node(tsk);
        } else {
-               addr->addr.id.ref = tsk->port.ref;
+               addr->addr.id.ref = tsk->ref;
                addr->addr.id.node = tipc_own_addr;
        }
 
@@ -518,7 +672,7 @@ static unsigned int tipc_poll(struct file *file, struct socket *sock,
                break;
        case SS_READY:
        case SS_CONNECTED:
-               if (!tsk->link_cong && !tipc_sk_conn_cong(tsk))
+               if (!tsk->link_cong && !tsk_conn_cong(tsk))
                        mask |= POLLOUT;
                /* fall thru' */
        case SS_CONNECTING:
@@ -549,7 +703,7 @@ static int tipc_sendmcast(struct  socket *sock, struct tipc_name_seq *seq,
                          struct iovec *iov, size_t dsz, long timeo)
 {
        struct sock *sk = sock->sk;
-       struct tipc_msg *mhdr = &tipc_sk(sk)->port.phdr;
+       struct tipc_msg *mhdr = &tipc_sk(sk)->phdr;
        struct sk_buff *buf;
        uint mtu;
        int rc;
@@ -579,6 +733,7 @@ new_mtu:
                        goto new_mtu;
                if (rc != -ELINKCONG)
                        break;
+               tipc_sk(sk)->link_cong = 1;
                rc = tipc_wait_for_sndmsg(sock, &timeo);
                if (rc)
                        kfree_skb_list(buf);
@@ -638,20 +793,19 @@ static int tipc_sk_proto_rcv(struct tipc_sock *tsk, u32 *dnode,
                             struct sk_buff *buf)
 {
        struct tipc_msg *msg = buf_msg(buf);
-       struct tipc_port *port = &tsk->port;
        int conn_cong;
 
        /* Ignore if connection cannot be validated: */
-       if (!port->connected || !tipc_port_peer_msg(port, msg))
+       if (!tsk_peer_msg(tsk, msg))
                goto exit;
 
-       port->probing_state = TIPC_CONN_OK;
+       tsk->probing_state = TIPC_CONN_OK;
 
        if (msg_type(msg) == CONN_ACK) {
-               conn_cong = tipc_sk_conn_cong(tsk);
+               conn_cong = tsk_conn_cong(tsk);
                tsk->sent_unacked -= msg_msgcnt(msg);
                if (conn_cong)
-                       tipc_sock_wakeup(tsk);
+                       tsk->sk.sk_write_space(&tsk->sk);
        } else if (msg_type(msg) == CONN_PROBE) {
                if (!tipc_msg_reverse(buf, dnode, TIPC_OK))
                        return TIPC_OK;
@@ -742,8 +896,7 @@ static int tipc_sendmsg(struct kiocb *iocb, struct socket *sock,
        DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name);
        struct sock *sk = sock->sk;
        struct tipc_sock *tsk = tipc_sk(sk);
-       struct tipc_port *port = &tsk->port;
-       struct tipc_msg *mhdr = &port->phdr;
+       struct tipc_msg *mhdr = &tsk->phdr;
        struct iovec *iov = m->msg_iov;
        u32 dnode, dport;
        struct sk_buff *buf;
@@ -774,13 +927,13 @@ static int tipc_sendmsg(struct kiocb *iocb, struct socket *sock,
                        rc = -EISCONN;
                        goto exit;
                }
-               if (tsk->port.published) {
+               if (tsk->published) {
                        rc = -EOPNOTSUPP;
                        goto exit;
                }
                if (dest->addrtype == TIPC_ADDR_NAME) {
-                       tsk->port.conn_type = dest->addr.name.name.type;
-                       tsk->port.conn_instance = dest->addr.name.name.instance;
+                       tsk->conn_type = dest->addr.name.name.type;
+                       tsk->conn_instance = dest->addr.name.name.instance;
                }
        }
        rc = dest_name_check(dest, m);
@@ -820,13 +973,14 @@ static int tipc_sendmsg(struct kiocb *iocb, struct socket *sock,
        }
 
 new_mtu:
-       mtu = tipc_node_get_mtu(dnode, tsk->port.ref);
+       mtu = tipc_node_get_mtu(dnode, tsk->ref);
        rc = tipc_msg_build(mhdr, iov, 0, dsz, mtu, &buf);
        if (rc < 0)
                goto exit;
 
        do {
-               rc = tipc_link_xmit(buf, dnode, tsk->port.ref);
+               TIPC_SKB_CB(buf)->wakeup_pending = tsk->link_cong;
+               rc = tipc_link_xmit(buf, dnode, tsk->ref);
                if (likely(rc >= 0)) {
                        if (sock->state != SS_READY)
                                sock->state = SS_CONNECTING;
@@ -835,10 +989,9 @@ new_mtu:
                }
                if (rc == -EMSGSIZE)
                        goto new_mtu;
-
                if (rc != -ELINKCONG)
                        break;
-
+               tsk->link_cong = 1;
                rc = tipc_wait_for_sndmsg(sock, &timeo);
                if (rc)
                        kfree_skb_list(buf);
@@ -873,8 +1026,8 @@ 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,
                                     (!tsk->link_cong &&
-                                     !tipc_sk_conn_cong(tsk)) ||
-                                    !tsk->port.connected);
+                                     !tsk_conn_cong(tsk)) ||
+                                    !tsk->connected);
                finish_wait(sk_sleep(sk), &wait);
        } while (!done);
        return 0;
@@ -897,11 +1050,10 @@ static int tipc_send_stream(struct kiocb *iocb, struct socket *sock,
 {
        struct sock *sk = sock->sk;
        struct tipc_sock *tsk = tipc_sk(sk);
-       struct tipc_port *port = &tsk->port;
-       struct tipc_msg *mhdr = &port->phdr;
+       struct tipc_msg *mhdr = &tsk->phdr;
        struct sk_buff *buf;
        DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name);
-       u32 ref = port->ref;
+       u32 ref = tsk->ref;
        int rc = -EINVAL;
        long timeo;
        u32 dnode;
@@ -929,16 +1081,16 @@ static int tipc_send_stream(struct kiocb *iocb, struct socket *sock,
        }
 
        timeo = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT);
-       dnode = tipc_port_peernode(port);
+       dnode = tsk_peer_node(tsk);
 
 next:
-       mtu = port->max_pkt;
+       mtu = tsk->max_pkt;
        send = min_t(uint, dsz - sent, TIPC_MAX_USER_MSG_SIZE);
        rc = tipc_msg_build(mhdr, m->msg_iov, sent, send, mtu, &buf);
        if (unlikely(rc < 0))
                goto exit;
        do {
-               if (likely(!tipc_sk_conn_cong(tsk))) {
+               if (likely(!tsk_conn_cong(tsk))) {
                        rc = tipc_link_xmit(buf, dnode, ref);
                        if (likely(!rc)) {
                                tsk->sent_unacked++;
@@ -948,11 +1100,12 @@ next:
                                goto next;
                        }
                        if (rc == -EMSGSIZE) {
-                               port->max_pkt = tipc_node_get_mtu(dnode, ref);
+                               tsk->max_pkt = tipc_node_get_mtu(dnode, ref);
                                goto next;
                        }
                        if (rc != -ELINKCONG)
                                break;
+                       tsk->link_cong = 1;
                }
                rc = tipc_wait_for_sndpkt(sock, &timeo);
                if (rc)
@@ -984,29 +1137,25 @@ static int tipc_send_packet(struct kiocb *iocb, struct socket *sock,
        return tipc_send_stream(iocb, sock, m, dsz);
 }
 
-/**
- * auto_connect - complete connection setup to a remote port
- * @tsk: tipc socket structure
- * @msg: peer's response message
- *
- * Returns 0 on success, errno otherwise
+/* tipc_sk_finish_conn - complete the setup of a connection
  */
-static int auto_connect(struct tipc_sock *tsk, struct tipc_msg *msg)
+static void tipc_sk_finish_conn(struct tipc_sock *tsk, u32 peer_port,
+                               u32 peer_node)
 {
-       struct tipc_port *port = &tsk->port;
-       struct socket *sock = tsk->sk.sk_socket;
-       struct tipc_portid peer;
-
-       peer.ref = msg_origport(msg);
-       peer.node = msg_orignode(msg);
-
-       __tipc_port_connect(port->ref, port, &peer);
-
-       if (msg_importance(msg) > TIPC_CRITICAL_IMPORTANCE)
-               return -EINVAL;
-       msg_set_importance(&port->phdr, (u32)msg_importance(msg));
-       sock->state = SS_CONNECTED;
-       return 0;
+       struct tipc_msg *msg = &tsk->phdr;
+
+       msg_set_destnode(msg, peer_node);
+       msg_set_destport(msg, peer_port);
+       msg_set_type(msg, TIPC_CONN_MSG);
+       msg_set_lookup_scope(msg, 0);
+       msg_set_hdr_sz(msg, SHORT_H_SIZE);
+
+       tsk->probing_interval = CONN_PROBING_INTERVAL;
+       tsk->probing_state = TIPC_CONN_OK;
+       tsk->connected = 1;
+       k_start_timer(&tsk->timer, tsk->probing_interval);
+       tipc_node_add_conn(peer_node, tsk->ref, peer_port);
+       tsk->max_pkt = tipc_node_get_mtu(peer_node, tsk->ref);
 }
 
 /**
@@ -1033,17 +1182,17 @@ static void set_orig_addr(struct msghdr *m, struct tipc_msg *msg)
 }
 
 /**
- * anc_data_recv - optionally capture ancillary data for received message
+ * tipc_sk_anc_data_recv - optionally capture ancillary data for received message
  * @m: descriptor for message info
  * @msg: received message header
- * @tport: TIPC port associated with message
+ * @tsk: TIPC port associated with message
  *
  * Note: Ancillary data is not captured if not requested by receiver.
  *
  * Returns 0 if successful, otherwise errno
  */
-static int anc_data_recv(struct msghdr *m, struct tipc_msg *msg,
-                        struct tipc_port *tport)
+static int tipc_sk_anc_data_recv(struct msghdr *m, struct tipc_msg *msg,
+                                struct tipc_sock *tsk)
 {
        u32 anc_data[3];
        u32 err;
@@ -1086,10 +1235,10 @@ static int anc_data_recv(struct msghdr *m, struct tipc_msg *msg,
                anc_data[2] = msg_nameupper(msg);
                break;
        case TIPC_CONN_MSG:
-               has_name = (tport->conn_type != 0);
-               anc_data[0] = tport->conn_type;
-               anc_data[1] = tport->conn_instance;
-               anc_data[2] = tport->conn_instance;
+               has_name = (tsk->conn_type != 0);
+               anc_data[0] = tsk->conn_type;
+               anc_data[1] = tsk->conn_instance;
+               anc_data[2] = tsk->conn_instance;
                break;
        default:
                has_name = 0;
@@ -1103,6 +1252,24 @@ static int anc_data_recv(struct msghdr *m, struct tipc_msg *msg,
        return 0;
 }
 
+static void tipc_sk_send_ack(struct tipc_sock *tsk, uint ack)
+{
+       struct sk_buff *buf = NULL;
+       struct tipc_msg *msg;
+       u32 peer_port = tsk_peer_port(tsk);
+       u32 dnode = tsk_peer_node(tsk);
+
+       if (!tsk->connected)
+               return;
+       buf = tipc_msg_create(CONN_MANAGER, CONN_ACK, INT_H_SIZE, 0, dnode,
+                             tipc_own_addr, peer_port, tsk->ref, TIPC_OK);
+       if (!buf)
+               return;
+       msg = buf_msg(buf);
+       msg_set_msgcnt(msg, ack);
+       tipc_link_xmit(buf, dnode, msg_link_selector(msg));
+}
+
 static int tipc_wait_for_rcvmsg(struct socket *sock, long *timeop)
 {
        struct sock *sk = sock->sk;
@@ -1153,7 +1320,6 @@ static int tipc_recvmsg(struct kiocb *iocb, struct socket *sock,
 {
        struct sock *sk = sock->sk;
        struct tipc_sock *tsk = tipc_sk(sk);
-       struct tipc_port *port = &tsk->port;
        struct sk_buff *buf;
        struct tipc_msg *msg;
        long timeo;
@@ -1188,7 +1354,7 @@ restart:
 
        /* Discard an empty non-errored message & try again */
        if ((!sz) && (!err)) {
-               advance_rx_queue(sk);
+               tsk_advance_rx_queue(sk);
                goto restart;
        }
 
@@ -1196,7 +1362,7 @@ restart:
        set_orig_addr(m, msg);
 
        /* Capture ancillary data (optional) */
-       res = anc_data_recv(m, msg, port);
+       res = tipc_sk_anc_data_recv(m, msg, tsk);
        if (res)
                goto exit;
 
@@ -1223,10 +1389,10 @@ restart:
        if (likely(!(flags & MSG_PEEK))) {
                if ((sock->state != SS_READY) &&
                    (++tsk->rcv_unacked >= TIPC_CONNACK_INTV)) {
-                       tipc_acknowledge(port->ref, tsk->rcv_unacked);
+                       tipc_sk_send_ack(tsk, tsk->rcv_unacked);
                        tsk->rcv_unacked = 0;
                }
-               advance_rx_queue(sk);
+               tsk_advance_rx_queue(sk);
        }
 exit:
        release_sock(sk);
@@ -1250,7 +1416,6 @@ static int tipc_recv_stream(struct kiocb *iocb, struct socket *sock,
 {
        struct sock *sk = sock->sk;
        struct tipc_sock *tsk = tipc_sk(sk);
-       struct tipc_port *port = &tsk->port;
        struct sk_buff *buf;
        struct tipc_msg *msg;
        long timeo;
@@ -1288,14 +1453,14 @@ restart:
 
        /* Discard an empty non-errored message & try again */
        if ((!sz) && (!err)) {
-               advance_rx_queue(sk);
+               tsk_advance_rx_queue(sk);
                goto 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, port);
+               res = tipc_sk_anc_data_recv(m, msg, tsk);
                if (res)
                        goto exit;
        }
@@ -1334,10 +1499,10 @@ restart:
        /* Consume received message (optional) */
        if (likely(!(flags & MSG_PEEK))) {
                if (unlikely(++tsk->rcv_unacked >= TIPC_CONNACK_INTV)) {
-                       tipc_acknowledge(port->ref, tsk->rcv_unacked);
+                       tipc_sk_send_ack(tsk, tsk->rcv_unacked);
                        tsk->rcv_unacked = 0;
                }
-               advance_rx_queue(sk);
+               tsk_advance_rx_queue(sk);
        }
 
        /* Loop around if more data is required */
@@ -1396,12 +1561,9 @@ static void tipc_data_ready(struct sock *sk)
 static int filter_connect(struct tipc_sock *tsk, struct sk_buff **buf)
 {
        struct sock *sk = &tsk->sk;
-       struct tipc_port *port = &tsk->port;
        struct socket *sock = sk->sk_socket;
        struct tipc_msg *msg = buf_msg(*buf);
-
        int retval = -TIPC_ERR_NO_PORT;
-       int res;
 
        if (msg_mcast(msg))
                return retval;
@@ -1409,16 +1571,23 @@ static int filter_connect(struct tipc_sock *tsk, 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(port, msg)) {
+               if (tsk_peer_msg(tsk, msg)) {
                        if (unlikely(msg_errcode(msg))) {
                                sock->state = SS_DISCONNECTING;
-                               __tipc_port_disconnect(port);
+                               tsk->connected = 0;
+                               /* let timer expire on it's own */
+                               tipc_node_remove_conn(tsk_peer_node(tsk),
+                                                     tsk->ref);
                        }
                        retval = TIPC_OK;
                }
                break;
        case SS_CONNECTING:
                /* Accept only ACK or NACK message */
+
+               if (unlikely(!msg_connected(msg)))
+                       break;
+
                if (unlikely(msg_errcode(msg))) {
                        sock->state = SS_DISCONNECTING;
                        sk->sk_err = ECONNREFUSED;
@@ -1426,17 +1595,17 @@ static int filter_connect(struct tipc_sock *tsk, struct sk_buff **buf)
                        break;
                }
 
-               if (unlikely(!msg_connected(msg)))
-                       break;
-
-               res = auto_connect(tsk, msg);
-               if (res) {
+               if (unlikely(msg_importance(msg) > TIPC_CRITICAL_IMPORTANCE)) {
                        sock->state = SS_DISCONNECTING;
-                       sk->sk_err = -res;
+                       sk->sk_err = EINVAL;
                        retval = TIPC_OK;
                        break;
                }
 
+               tipc_sk_finish_conn(tsk, msg_origport(msg), msg_orignode(msg));
+               msg_set_importance(&tsk->phdr, msg_importance(msg));
+               sock->state = SS_CONNECTED;
+
                /* If an incoming message is an 'ACK-', it should be
                 * discarded here because it doesn't contain useful
                 * data. In addition, we should try to wake up
@@ -1518,6 +1687,13 @@ static int filter_rcv(struct sock *sk, struct sk_buff *buf)
        if (unlikely(msg_user(msg) == CONN_MANAGER))
                return tipc_sk_proto_rcv(tsk, &onode, buf);
 
+       if (unlikely(msg_user(msg) == SOCK_WAKEUP)) {
+               kfree_skb(buf);
+               tsk->link_cong = 0;
+               sk->sk_write_space(sk);
+               return TIPC_OK;
+       }
+
        /* Reject message if it is wrong sort of message for socket */
        if (msg_type(msg) > TIPC_DIRECT_MSG)
                return -TIPC_ERR_NO_PORT;
@@ -1585,7 +1761,6 @@ static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *buf)
 int tipc_sk_rcv(struct sk_buff *buf)
 {
        struct tipc_sock *tsk;
-       struct tipc_port *port;
        struct sock *sk;
        u32 dport = msg_destport(buf_msg(buf));
        int rc = TIPC_OK;
@@ -1593,13 +1768,11 @@ int tipc_sk_rcv(struct sk_buff *buf)
        u32 dnode;
 
        /* Validate destination and message */
-       port = tipc_port_lock(dport);
-       if (unlikely(!port)) {
+       tsk = tipc_sk_get(dport);
+       if (unlikely(!tsk)) {
                rc = tipc_msg_eval(buf, &dnode);
                goto exit;
        }
-
-       tsk = tipc_port_to_sock(port);
        sk = &tsk->sk;
 
        /* Queue message */
@@ -1615,8 +1788,7 @@ int tipc_sk_rcv(struct sk_buff *buf)
                        rc = -TIPC_ERR_OVERLOAD;
        }
        bh_unlock_sock(sk);
-       tipc_port_unlock(port);
-
+       tipc_sk_put(tsk);
        if (likely(!rc))
                return 0;
 exit:
@@ -1803,10 +1975,8 @@ 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_port *new_port;
+       struct tipc_sock *new_tsock;
        struct tipc_msg *msg;
-       struct tipc_portid peer;
-       u32 new_ref;
        long timeo;
        int res;
 
@@ -1828,8 +1998,7 @@ static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags)
                goto exit;
 
        new_sk = new_sock->sk;
-       new_port = &tipc_sk(new_sk)->port;
-       new_ref = new_port->ref;
+       new_tsock = tipc_sk(new_sk);
        msg = buf_msg(buf);
 
        /* we lock on new_sk; but lockdep sees the lock on sk */
@@ -1839,18 +2008,16 @@ static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags)
         * Reject any stray messages received by new socket
         * before the socket lock was taken (very, very unlikely)
         */
-       reject_rx_queue(new_sk);
+       tsk_rej_rx_queue(new_sk);
 
        /* Connect new socket to it's peer */
-       peer.ref = msg_origport(msg);
-       peer.node = msg_orignode(msg);
-       tipc_port_connect(new_ref, &peer);
+       tipc_sk_finish_conn(new_tsock, msg_origport(msg), msg_orignode(msg));
        new_sock->state = SS_CONNECTED;
 
-       tipc_port_set_importance(new_port, msg_importance(msg));
+       tsk_set_importance(new_tsock, msg_importance(msg));
        if (msg_named(msg)) {
-               new_port->conn_type = msg_nametype(msg);
-               new_port->conn_instance = msg_nameinst(msg);
+               new_tsock->conn_type = msg_nametype(msg);
+               new_tsock->conn_instance = msg_nameinst(msg);
        }
 
        /*
@@ -1860,7 +2027,7 @@ static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags)
        if (!msg_data_sz(msg)) {
                struct msghdr m = {NULL,};
 
-               advance_rx_queue(sk);
+               tsk_advance_rx_queue(sk);
                tipc_send_packet(NULL, new_sock, &m, 0);
        } else {
                __skb_dequeue(&sk->sk_receive_queue);
@@ -1886,9 +2053,8 @@ static int tipc_shutdown(struct socket *sock, int how)
 {
        struct sock *sk = sock->sk;
        struct tipc_sock *tsk = tipc_sk(sk);
-       struct tipc_port *port = &tsk->port;
        struct sk_buff *buf;
-       u32 peer;
+       u32 dnode;
        int res;
 
        if (how != SHUT_RDWR)
@@ -1908,15 +2074,21 @@ restart:
                                kfree_skb(buf);
                                goto restart;
                        }
-                       tipc_port_disconnect(port->ref);
-                       if (tipc_msg_reverse(buf, &peer, TIPC_CONN_SHUTDOWN))
-                               tipc_link_xmit(buf, peer, 0);
+                       if (tipc_msg_reverse(buf, &dnode, TIPC_CONN_SHUTDOWN))
+                               tipc_link_xmit(buf, dnode, tsk->ref);
+                       tipc_node_remove_conn(dnode, tsk->ref);
                } else {
-                       tipc_port_shutdown(port->ref);
+                       dnode = tsk_peer_node(tsk);
+                       buf = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE,
+                                             TIPC_CONN_MSG, SHORT_H_SIZE,
+                                             0, dnode, tipc_own_addr,
+                                             tsk_peer_port(tsk),
+                                             tsk->ref, TIPC_CONN_SHUTDOWN);
+                       tipc_link_xmit(buf, dnode, tsk->ref);
                }
-
+               tsk->connected = 0;
                sock->state = SS_DISCONNECTING;
-
+               tipc_node_remove_conn(dnode, tsk->ref);
                /* fall through */
 
        case SS_DISCONNECTING:
@@ -1937,6 +2109,432 @@ restart:
        return res;
 }
 
+static void tipc_sk_timeout(unsigned long ref)
+{
+       struct tipc_sock *tsk;
+       struct sock *sk;
+       struct sk_buff *buf = NULL;
+       u32 peer_port, peer_node;
+
+       tsk = tipc_sk_get(ref);
+       if (!tsk)
+               return;
+
+       sk = &tsk->sk;
+       bh_lock_sock(sk);
+       if (!tsk->connected) {
+               bh_unlock_sock(sk);
+               goto exit;
+       }
+       peer_port = tsk_peer_port(tsk);
+       peer_node = tsk_peer_node(tsk);
+
+       if (tsk->probing_state == TIPC_CONN_PROBING) {
+               /* Previous probe not answered -> self abort */
+               buf = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE, TIPC_CONN_MSG,
+                                     SHORT_H_SIZE, 0, tipc_own_addr,
+                                     peer_node, ref, peer_port,
+                                     TIPC_ERR_NO_PORT);
+       } else {
+               buf = tipc_msg_create(CONN_MANAGER, CONN_PROBE, INT_H_SIZE,
+                                     0, peer_node, tipc_own_addr,
+                                     peer_port, ref, TIPC_OK);
+               tsk->probing_state = TIPC_CONN_PROBING;
+               k_start_timer(&tsk->timer, tsk->probing_interval);
+       }
+       bh_unlock_sock(sk);
+       if (buf)
+               tipc_link_xmit(buf, peer_node, ref);
+exit:
+       tipc_sk_put(tsk);
+}
+
+static int tipc_sk_publish(struct tipc_sock *tsk, uint scope,
+                          struct tipc_name_seq const *seq)
+{
+       struct publication *publ;
+       u32 key;
+
+       if (tsk->connected)
+               return -EINVAL;
+       key = tsk->ref + tsk->pub_count + 1;
+       if (key == tsk->ref)
+               return -EADDRINUSE;
+
+       publ = tipc_nametbl_publish(seq->type, seq->lower, seq->upper,
+                                   scope, tsk->ref, key);
+       if (unlikely(!publ))
+               return -EINVAL;
+
+       list_add(&publ->pport_list, &tsk->publications);
+       tsk->pub_count++;
+       tsk->published = 1;
+       return 0;
+}
+
+static int tipc_sk_withdraw(struct tipc_sock *tsk, uint scope,
+                           struct tipc_name_seq const *seq)
+{
+       struct publication *publ;
+       struct publication *safe;
+       int rc = -EINVAL;
+
+       list_for_each_entry_safe(publ, safe, &tsk->publications, pport_list) {
+               if (seq) {
+                       if (publ->scope != scope)
+                               continue;
+                       if (publ->type != seq->type)
+                               continue;
+                       if (publ->lower != seq->lower)
+                               continue;
+                       if (publ->upper != seq->upper)
+                               break;
+                       tipc_nametbl_withdraw(publ->type, publ->lower,
+                                             publ->ref, publ->key);
+                       rc = 0;
+                       break;
+               }
+               tipc_nametbl_withdraw(publ->type, publ->lower,
+                                     publ->ref, publ->key);
+               rc = 0;
+       }
+       if (list_empty(&tsk->publications))
+               tsk->published = 0;
+       return rc;
+}
+
+static int tipc_sk_show(struct tipc_sock *tsk, char *buf,
+                       int len, int full_id)
+{
+       struct publication *publ;
+       int ret;
+
+       if (full_id)
+               ret = tipc_snprintf(buf, len, "<%u.%u.%u:%u>:",
+                                   tipc_zone(tipc_own_addr),
+                                   tipc_cluster(tipc_own_addr),
+                                   tipc_node(tipc_own_addr), tsk->ref);
+       else
+               ret = tipc_snprintf(buf, len, "%-10u:", tsk->ref);
+
+       if (tsk->connected) {
+               u32 dport = tsk_peer_port(tsk);
+               u32 destnode = tsk_peer_node(tsk);
+
+               ret += tipc_snprintf(buf + ret, len - ret,
+                                    " connected to <%u.%u.%u:%u>",
+                                    tipc_zone(destnode),
+                                    tipc_cluster(destnode),
+                                    tipc_node(destnode), dport);
+               if (tsk->conn_type != 0)
+                       ret += tipc_snprintf(buf + ret, len - ret,
+                                            " via {%u,%u}", tsk->conn_type,
+                                            tsk->conn_instance);
+       } else if (tsk->published) {
+               ret += tipc_snprintf(buf + ret, len - ret, " bound to");
+               list_for_each_entry(publ, &tsk->publications, pport_list) {
+                       if (publ->lower == publ->upper)
+                               ret += tipc_snprintf(buf + ret, len - ret,
+                                                    " {%u,%u}", publ->type,
+                                                    publ->lower);
+                       else
+                               ret += tipc_snprintf(buf + ret, len - ret,
+                                                    " {%u,%u,%u}", publ->type,
+                                                    publ->lower, publ->upper);
+               }
+       }
+       ret += tipc_snprintf(buf + ret, len - ret, "\n");
+       return ret;
+}
+
+struct sk_buff *tipc_sk_socks_show(void)
+{
+       struct sk_buff *buf;
+       struct tlv_desc *rep_tlv;
+       char *pb;
+       int pb_len;
+       struct tipc_sock *tsk;
+       int str_len = 0;
+       u32 ref = 0;
+
+       buf = tipc_cfg_reply_alloc(TLV_SPACE(ULTRA_STRING_MAX_LEN));
+       if (!buf)
+               return NULL;
+       rep_tlv = (struct tlv_desc *)buf->data;
+       pb = TLV_DATA(rep_tlv);
+       pb_len = ULTRA_STRING_MAX_LEN;
+
+       tsk = tipc_sk_get_next(&ref);
+       for (; tsk; tsk = tipc_sk_get_next(&ref)) {
+               lock_sock(&tsk->sk);
+               str_len += tipc_sk_show(tsk, pb + str_len,
+                                       pb_len - str_len, 0);
+               release_sock(&tsk->sk);
+               tipc_sk_put(tsk);
+       }
+       str_len += 1;   /* for "\0" */
+       skb_put(buf, TLV_SPACE(str_len));
+       TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
+
+       return buf;
+}
+
+/* tipc_sk_reinit: set non-zero address in all existing sockets
+ *                 when we go from standalone to network mode.
+ */
+void tipc_sk_reinit(void)
+{
+       struct tipc_msg *msg;
+       u32 ref = 0;
+       struct tipc_sock *tsk = tipc_sk_get_next(&ref);
+
+       for (; tsk; tsk = tipc_sk_get_next(&ref)) {
+               lock_sock(&tsk->sk);
+               msg = &tsk->phdr;
+               msg_set_prevnode(msg, tipc_own_addr);
+               msg_set_orignode(msg, tipc_own_addr);
+               release_sock(&tsk->sk);
+               tipc_sk_put(tsk);
+       }
+}
+
+/**
+ * struct reference - TIPC socket reference entry
+ * @tsk: pointer to socket associated with reference entry
+ * @ref: reference value for socket (combines instance & array index info)
+ */
+struct reference {
+       struct tipc_sock *tsk;
+       u32 ref;
+};
+
+/**
+ * struct tipc_ref_table - table of TIPC socket reference entries
+ * @entries: pointer to array of reference entries
+ * @capacity: array index of first unusable entry
+ * @init_point: array index of first uninitialized entry
+ * @first_free: array index of first unused socket reference entry
+ * @last_free: array index of last unused socket reference entry
+ * @index_mask: bitmask for array index portion of reference values
+ * @start_mask: initial value for instance value portion of reference values
+ */
+struct ref_table {
+       struct reference *entries;
+       u32 capacity;
+       u32 init_point;
+       u32 first_free;
+       u32 last_free;
+       u32 index_mask;
+       u32 start_mask;
+};
+
+/* Socket reference table consists of 2**N entries.
+ *
+ * State       Socket ptr      Reference
+ * -----        ----------      ---------
+ * In use        non-NULL       XXXX|own index
+ *                             (XXXX changes each time entry is acquired)
+ * Free            NULL         YYYY|next free index
+ *                             (YYYY is one more than last used XXXX)
+ * Uninitialized   NULL         0
+ *
+ * Entry 0 is not used; this allows index 0 to denote the end of the free list.
+ *
+ * Note that a reference value of 0 does not necessarily indicate that an
+ * entry is uninitialized, since the last entry in the free list could also
+ * have a reference value of 0 (although this is unlikely).
+ */
+
+static struct ref_table tipc_ref_table;
+
+static DEFINE_RWLOCK(ref_table_lock);
+
+/**
+ * tipc_ref_table_init - create reference table for sockets
+ */
+int tipc_sk_ref_table_init(u32 req_sz, u32 start)
+{
+       struct reference *table;
+       u32 actual_sz;
+
+       /* account for unused entry, then round up size to a power of 2 */
+
+       req_sz++;
+       for (actual_sz = 16; actual_sz < req_sz; actual_sz <<= 1) {
+               /* do nothing */
+       };
+
+       /* allocate table & mark all entries as uninitialized */
+       table = vzalloc(actual_sz * sizeof(struct reference));
+       if (table == NULL)
+               return -ENOMEM;
+
+       tipc_ref_table.entries = table;
+       tipc_ref_table.capacity = req_sz;
+       tipc_ref_table.init_point = 1;
+       tipc_ref_table.first_free = 0;
+       tipc_ref_table.last_free = 0;
+       tipc_ref_table.index_mask = actual_sz - 1;
+       tipc_ref_table.start_mask = start & ~tipc_ref_table.index_mask;
+
+       return 0;
+}
+
+/**
+ * tipc_ref_table_stop - destroy reference table for sockets
+ */
+void tipc_sk_ref_table_stop(void)
+{
+       if (!tipc_ref_table.entries)
+               return;
+       vfree(tipc_ref_table.entries);
+       tipc_ref_table.entries = NULL;
+}
+
+/* tipc_ref_acquire - create reference to a socket
+ *
+ * Register an socket pointer in the reference table.
+ * Returns a unique reference value that is used from then on to retrieve the
+ * socket pointer, or to determine if the socket has been deregistered.
+ */
+u32 tipc_sk_ref_acquire(struct tipc_sock *tsk)
+{
+       u32 index;
+       u32 index_mask;
+       u32 next_plus_upper;
+       u32 ref = 0;
+       struct reference *entry;
+
+       if (unlikely(!tsk)) {
+               pr_err("Attempt to acquire ref. to non-existent obj\n");
+               return 0;
+       }
+       if (unlikely(!tipc_ref_table.entries)) {
+               pr_err("Ref. table not found in acquisition attempt\n");
+               return 0;
+       }
+
+       /* Take a free entry, if available; otherwise initialize a new one */
+       write_lock_bh(&ref_table_lock);
+       index = tipc_ref_table.first_free;
+       entry = &tipc_ref_table.entries[index];
+
+       if (likely(index)) {
+               index = tipc_ref_table.first_free;
+               entry = &tipc_ref_table.entries[index];
+               index_mask = tipc_ref_table.index_mask;
+               next_plus_upper = entry->ref;
+               tipc_ref_table.first_free = next_plus_upper & index_mask;
+               ref = (next_plus_upper & ~index_mask) + index;
+               entry->tsk = tsk;
+       } else if (tipc_ref_table.init_point < tipc_ref_table.capacity) {
+               index = tipc_ref_table.init_point++;
+               entry = &tipc_ref_table.entries[index];
+               ref = tipc_ref_table.start_mask + index;
+       }
+
+       if (ref) {
+               entry->ref = ref;
+               entry->tsk = tsk;
+       }
+       write_unlock_bh(&ref_table_lock);
+       return ref;
+}
+
+/* tipc_sk_ref_discard - invalidate reference to an socket
+ *
+ * Disallow future references to an socket and free up the entry for re-use.
+ */
+void tipc_sk_ref_discard(u32 ref)
+{
+       struct reference *entry;
+       u32 index;
+       u32 index_mask;
+
+       if (unlikely(!tipc_ref_table.entries)) {
+               pr_err("Ref. table not found during discard attempt\n");
+               return;
+       }
+
+       index_mask = tipc_ref_table.index_mask;
+       index = ref & index_mask;
+       entry = &tipc_ref_table.entries[index];
+
+       write_lock_bh(&ref_table_lock);
+
+       if (unlikely(!entry->tsk)) {
+               pr_err("Attempt to discard ref. to non-existent socket\n");
+               goto exit;
+       }
+       if (unlikely(entry->ref != ref)) {
+               pr_err("Attempt to discard non-existent reference\n");
+               goto exit;
+       }
+
+       /* Mark entry as unused; increment instance part of entry's
+        *   reference to invalidate any subsequent references
+        */
+
+       entry->tsk = NULL;
+       entry->ref = (ref & ~index_mask) + (index_mask + 1);
+
+       /* Append entry to free entry list */
+       if (unlikely(tipc_ref_table.first_free == 0))
+               tipc_ref_table.first_free = index;
+       else
+               tipc_ref_table.entries[tipc_ref_table.last_free].ref |= index;
+       tipc_ref_table.last_free = index;
+exit:
+       write_unlock_bh(&ref_table_lock);
+}
+
+/* tipc_sk_get - find referenced socket and return pointer to it
+ */
+struct tipc_sock *tipc_sk_get(u32 ref)
+{
+       struct reference *entry;
+       struct tipc_sock *tsk;
+
+       if (unlikely(!tipc_ref_table.entries))
+               return NULL;
+       read_lock_bh(&ref_table_lock);
+       entry = &tipc_ref_table.entries[ref & tipc_ref_table.index_mask];
+       tsk = entry->tsk;
+       if (likely(tsk && (entry->ref == ref)))
+               sock_hold(&tsk->sk);
+       else
+               tsk = NULL;
+       read_unlock_bh(&ref_table_lock);
+       return tsk;
+}
+
+/* tipc_sk_get_next - lock & return next socket after referenced one
+*/
+struct tipc_sock *tipc_sk_get_next(u32 *ref)
+{
+       struct reference *entry;
+       struct tipc_sock *tsk = NULL;
+       uint index = *ref & tipc_ref_table.index_mask;
+
+       read_lock_bh(&ref_table_lock);
+       while (++index < tipc_ref_table.capacity) {
+               entry = &tipc_ref_table.entries[index];
+               if (!entry->tsk)
+                       continue;
+               tsk = entry->tsk;
+               sock_hold(&tsk->sk);
+               *ref = entry->ref;
+               break;
+       }
+       read_unlock_bh(&ref_table_lock);
+       return tsk;
+}
+
+static void tipc_sk_put(struct tipc_sock *tsk)
+{
+       sock_put(&tsk->sk);
+}
+
 /**
  * tipc_setsockopt - set socket option
  * @sock: socket structure
@@ -1955,7 +2553,6 @@ static int tipc_setsockopt(struct socket *sock, int lvl, int opt,
 {
        struct sock *sk = sock->sk;
        struct tipc_sock *tsk = tipc_sk(sk);
-       struct tipc_port *port = &tsk->port;
        u32 value;
        int res;
 
@@ -1973,16 +2570,16 @@ static int tipc_setsockopt(struct socket *sock, int lvl, int opt,
 
        switch (opt) {
        case TIPC_IMPORTANCE:
-               tipc_port_set_importance(port, value);
+               res = tsk_set_importance(tsk, value);
                break;
        case TIPC_SRC_DROPPABLE:
                if (sock->type != SOCK_STREAM)
-                       tipc_port_set_unreliable(port, value);
+                       tsk_set_unreliable(tsk, value);
                else
                        res = -ENOPROTOOPT;
                break;
        case TIPC_DEST_DROPPABLE:
-               tipc_port_set_unreturnable(port, value);
+               tsk_set_unreturnable(tsk, value);
                break;
        case TIPC_CONN_TIMEOUT:
                tipc_sk(sk)->conn_timeout = value;
@@ -2015,7 +2612,6 @@ static int tipc_getsockopt(struct socket *sock, int lvl, int opt,
 {
        struct sock *sk = sock->sk;
        struct tipc_sock *tsk = tipc_sk(sk);
-       struct tipc_port *port = &tsk->port;
        int len;
        u32 value;
        int res;
@@ -2032,16 +2628,16 @@ static int tipc_getsockopt(struct socket *sock, int lvl, int opt,
 
        switch (opt) {
        case TIPC_IMPORTANCE:
-               value = tipc_port_importance(port);
+               value = tsk_importance(tsk);
                break;
        case TIPC_SRC_DROPPABLE:
-               value = tipc_port_unreliable(port);
+               value = tsk_unreliable(tsk);
                break;
        case TIPC_DEST_DROPPABLE:
-               value = tipc_port_unreturnable(port);
+               value = tsk_unreturnable(tsk);
                break;
        case TIPC_CONN_TIMEOUT:
-               value = tipc_sk(sk)->conn_timeout;
+               value = tsk->conn_timeout;
                /* no need to set "res", since already 0 at this point */
                break;
        case TIPC_NODE_RECVQ_DEPTH:
index 43b75b3cecedb9b3bee4fd6a9a42a8f5a4cbcf0b..baa43d03901e5b093238bf4a92b01135c109d5a2 100644 (file)
 #ifndef _TIPC_SOCK_H
 #define _TIPC_SOCK_H
 
-#include "port.h"
 #include <net/sock.h>
 
-#define TIPC_CONN_OK      0
-#define TIPC_CONN_PROBING 1
-
-/**
- * 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
- * @dupl_rcvcnt: number of bytes counted twice, in both backlog and rcv queue
- * @link_cong: non-zero if owner must sleep because of link congestion
- * @sent_unacked: # messages sent by socket, and not yet acked by peer
- * @rcv_unacked: # messages read by user, but not yet acked back to peer
- */
-
-struct tipc_sock {
-       struct sock sk;
-       struct tipc_port port;
-       unsigned int conn_timeout;
-       atomic_t dupl_rcvcnt;
-       int link_cong;
-       uint sent_unacked;
-       uint rcv_unacked;
-};
-
-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);
-}
-
-static inline int tipc_sk_conn_cong(struct tipc_sock *tsk)
-{
-       return tsk->sent_unacked >= TIPC_FLOWCTRL_WIN;
-}
-
+#define TIPC_CONNACK_INTV         256
+#define TIPC_FLOWCTRL_WIN        (TIPC_CONNACK_INTV * 2)
+#define TIPC_CONN_OVERLOAD_LIMIT ((TIPC_FLOWCTRL_WIN * 2 + 1) * \
+                                 SKB_TRUESIZE(TIPC_MAX_USER_MSG_SIZE))
 int tipc_sk_rcv(struct sk_buff *buf);
-
+struct sk_buff *tipc_sk_socks_show(void);
 void tipc_sk_mcast_rcv(struct sk_buff *buf);
+void tipc_sk_reinit(void);
+int tipc_sk_ref_table_init(u32 requested_size, u32 start);
+void tipc_sk_ref_table_stop(void);
 
 #endif
index 642437231ad5d2da2e7c9de5bd4494b082f3472e..31b5cb232a4371e3728ed9e7b934c3560f9ed92c 100644 (file)
@@ -36,7 +36,6 @@
 
 #include "core.h"
 #include "name_table.h"
-#include "port.h"
 #include "subscr.h"
 
 /**
index f3fef93325a8977c0e22ffe8cb0fd9a2302cff0e..1a779b1e85100b501c1f0cde29cbfaa0d98fb4eb 100644 (file)
@@ -47,6 +47,13 @@ static struct ctl_table tipc_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
+       {
+               .procname       = "named_timeout",
+               .data           = &sysctl_tipc_named_timeout,
+               .maxlen         = sizeof(sysctl_tipc_named_timeout),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec,
+       },
        {}
 };
 
index afee5e0455ea460b9b3d2e39c27e7eb0d881fa9f..c6620aa679e079bcf6693ac92cf4760435212081 100644 (file)
@@ -492,12 +492,6 @@ int wiphy_register(struct wiphy *wiphy)
        int i;
        u16 ifmodes = wiphy->interface_modes;
 
-       /*
-        * There are major locking problems in nl80211/mac80211 for CSA,
-        * disable for all drivers until this has been reworked.
-        */
-       wiphy->flags &= ~WIPHY_FLAG_HAS_CHANNEL_SWITCH;
-
 #ifdef CONFIG_PM
        if (WARN_ON(wiphy->wowlan &&
                    (wiphy->wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) &&
@@ -635,6 +629,9 @@ int wiphy_register(struct wiphy *wiphy)
        if (IS_ERR(rdev->wiphy.debugfsdir))
                rdev->wiphy.debugfsdir = NULL;
 
+       cfg80211_debugfs_rdev_add(rdev);
+       nl80211_notify_wiphy(rdev, NL80211_CMD_NEW_WIPHY);
+
        if (wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) {
                struct regulatory_request request;
 
@@ -646,8 +643,6 @@ int wiphy_register(struct wiphy *wiphy)
                nl80211_send_reg_change_event(&request);
        }
 
-       cfg80211_debugfs_rdev_add(rdev);
-
        rdev->wiphy.registered = true;
        rtnl_unlock();
 
@@ -659,8 +654,6 @@ int wiphy_register(struct wiphy *wiphy)
                return res;
        }
 
-       nl80211_notify_wiphy(rdev, NL80211_CMD_NEW_WIPHY);
-
        return 0;
 }
 EXPORT_SYMBOL(wiphy_register);
index 266766b8d80b61455565cc43779a6e229ed7710d..369fc334fdadede142c86f9676dd752761d4f4c4 100644 (file)
@@ -605,7 +605,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
 }
 
 bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm,
-                     const u8 *buf, size_t len, u32 flags, gfp_t gfp)
+                     const u8 *buf, size_t len, u32 flags)
 {
        struct wiphy *wiphy = wdev->wiphy;
        struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
@@ -648,7 +648,7 @@ bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm,
                /* Indicate the received Action frame to user space */
                if (nl80211_send_mgmt(rdev, wdev, reg->nlportid,
                                      freq, sig_mbm,
-                                     buf, len, flags, gfp))
+                                     buf, len, flags, GFP_ATOMIC))
                        continue;
 
                result = true;
index df7b1332a1ec2fa80834b94c233f38a427a0f350..3011401f52c0a34317b2310dfa59912d4afe760c 100644 (file)
@@ -6033,7 +6033,6 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
        const struct cfg80211_bss_ies *ies;
        void *hdr;
        struct nlattr *bss;
-       bool tsf = false;
 
        ASSERT_WDEV_LOCK(wdev);
 
@@ -6060,18 +6059,27 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
                goto nla_put_failure;
 
        rcu_read_lock();
+       /* indicate whether we have probe response data or not */
+       if (rcu_access_pointer(res->proberesp_ies) &&
+           nla_put_flag(msg, NL80211_BSS_PRESP_DATA))
+               goto fail_unlock_rcu;
+
+       /* this pointer prefers to be pointed to probe response data
+        * but is always valid
+        */
        ies = rcu_dereference(res->ies);
        if (ies) {
                if (nla_put_u64(msg, NL80211_BSS_TSF, ies->tsf))
                        goto fail_unlock_rcu;
-               tsf = true;
                if (ies->len && nla_put(msg, NL80211_BSS_INFORMATION_ELEMENTS,
                                        ies->len, ies->data))
                        goto fail_unlock_rcu;
        }
+
+       /* and this pointer is always (unless driver didn't know) beacon data */
        ies = rcu_dereference(res->beacon_ies);
-       if (ies) {
-               if (!tsf && nla_put_u64(msg, NL80211_BSS_TSF, ies->tsf))
+       if (ies && ies->from_beacon) {
+               if (nla_put_u64(msg, NL80211_BSS_BEACON_TSF, ies->tsf))
                        goto fail_unlock_rcu;
                if (ies->len && nla_put(msg, NL80211_BSS_BEACON_IES,
                                        ies->len, ies->data))
index 0798c62e60858cb81d1df3d4829414665808268b..620a4b40d4662f8f5718da6b28aeeb281c573224 100644 (file)
@@ -884,6 +884,7 @@ struct cfg80211_bss*
 cfg80211_inform_bss_width(struct wiphy *wiphy,
                          struct ieee80211_channel *rx_channel,
                          enum nl80211_bss_scan_width scan_width,
+                         enum cfg80211_bss_frame_type ftype,
                          const u8 *bssid, u64 tsf, u16 capability,
                          u16 beacon_interval, const u8 *ie, size_t ielen,
                          s32 signal, gfp_t gfp)
@@ -911,21 +912,32 @@ cfg80211_inform_bss_width(struct wiphy *wiphy,
        tmp.pub.beacon_interval = beacon_interval;
        tmp.pub.capability = capability;
        /*
-        * Since we do not know here whether the IEs are from a Beacon or Probe
+        * If we do not know here whether the IEs are from a Beacon or Probe
         * Response frame, we need to pick one of the options and only use it
         * with the driver that does not provide the full Beacon/Probe Response
         * frame. Use Beacon frame pointer to avoid indicating that this should
         * override the IEs pointer should we have received an earlier
         * indication of Probe Response data.
         */
-       ies = kmalloc(sizeof(*ies) + ielen, gfp);
+       ies = kzalloc(sizeof(*ies) + ielen, gfp);
        if (!ies)
                return NULL;
        ies->len = ielen;
        ies->tsf = tsf;
+       ies->from_beacon = false;
        memcpy(ies->data, ie, ielen);
 
-       rcu_assign_pointer(tmp.pub.beacon_ies, ies);
+       switch (ftype) {
+       case CFG80211_BSS_FTYPE_BEACON:
+               ies->from_beacon = true;
+               /* fall through to assign */
+       case CFG80211_BSS_FTYPE_UNKNOWN:
+               rcu_assign_pointer(tmp.pub.beacon_ies, ies);
+               break;
+       case CFG80211_BSS_FTYPE_PRESP:
+               rcu_assign_pointer(tmp.pub.proberesp_ies, ies);
+               break;
+       }
        rcu_assign_pointer(tmp.pub.ies, ies);
 
        signal_valid = abs(rx_channel->center_freq - channel->center_freq) <=
@@ -982,11 +994,12 @@ cfg80211_inform_bss_width_frame(struct wiphy *wiphy,
        if (!channel)
                return NULL;
 
-       ies = kmalloc(sizeof(*ies) + ielen, gfp);
+       ies = kzalloc(sizeof(*ies) + ielen, gfp);
        if (!ies)
                return NULL;
        ies->len = ielen;
        ies->tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp);
+       ies->from_beacon = ieee80211_is_beacon(mgmt->frame_control);
        memcpy(ies->data, mgmt->u.probe_resp.variable, ielen);
 
        if (ieee80211_is_probe_resp(mgmt->frame_control))
index c51e8f7b8653cb167aba13f61c2d7520d615c31c..499d6c18a8ce4366a5fe61184eb7416bfb060401 100644 (file)
@@ -166,11 +166,7 @@ static int xfrm_output_gso(struct sk_buff *skb)
                err = xfrm_output2(segs);
 
                if (unlikely(err)) {
-                       while ((segs = nskb)) {
-                               nskb = segs->next;
-                               segs->next = NULL;
-                               kfree_skb(segs);
-                       }
+                       kfree_skb_list(nskb);
                        return err;
                }
 
index 31a731e06f5022afd7c040d5688840491b228e9d..b385bcbbf2f58e03d21ec155a304cf3baed7cdd8 100755 (executable)
@@ -2133,7 +2133,7 @@ sub process {
 # Check for improperly formed commit descriptions
                if ($in_commit_log &&
                    $line =~ /\bcommit\s+[0-9a-f]{5,}/i &&
-                   $line !~ /\b[Cc]ommit [0-9a-f]{12,16} \("/) {
+                   $line !~ /\b[Cc]ommit [0-9a-f]{12,40} \("/) {
                        $line =~ /\b(c)ommit\s+([0-9a-f]{5,})/i;
                        my $init_char = $1;
                        my $orig_commit = lc($2);
@@ -2141,7 +2141,7 @@ sub process {
                        my $desc = 'commit description';
                        ($id, $desc) = git_commit_info($orig_commit, $id, $desc);
                        ERROR("GIT_COMMIT_ID",
-                             "Please use 12 to 16 chars for the git commit ID like: '${init_char}ommit $id (\"$desc\")'\n" . $herecurr);
+                             "Please use 12 or more chars for the git commit ID like: '${init_char}ommit $id (\"$desc\")'\n" . $herecurr);
                }
 
 # Check for added, moved or deleted files
index 16a07cfa4d3469d0a386cc1264afb07c6241bcea..70bea942b4135b6a607bdb8ded0f50f0142aba40 100755 (executable)
@@ -2085,6 +2085,7 @@ sub dump_function($$) {
     $prototype =~ s/^noinline +//;
     $prototype =~ s/__init +//;
     $prototype =~ s/__init_or_module +//;
+    $prototype =~ s/__meminit +//;
     $prototype =~ s/__must_check +//;
     $prototype =~ s/__weak +//;
     my $define = $prototype =~ s/^#\s*define\s+//; #ak added
index b90a68c4e2c4277035b21f873af64efcd95bf782..6d0cad16f00265a1dc31d8a0804984040fb47995 100644 (file)
@@ -27,8 +27,8 @@ DEFINE_SPINLOCK(key_serial_lock);
 struct rb_root key_user_tree; /* tree of quota records indexed by UID */
 DEFINE_SPINLOCK(key_user_lock);
 
-unsigned int key_quota_root_maxkeys = 200;     /* root's key count quota */
-unsigned int key_quota_root_maxbytes = 20000;  /* root's key space quota */
+unsigned int key_quota_root_maxkeys = 1000000; /* root's key count quota */
+unsigned int key_quota_root_maxbytes = 25000000; /* root's key space quota */
 unsigned int key_quota_maxkeys = 200;          /* general key count quota */
 unsigned int key_quota_maxbytes = 20000;       /* general key space quota */
 
index a3386d119425eb8367194063470efe017eef622b..bed745c8b1a30d47a173fd7d96322aebb2d09c9c 100644 (file)
@@ -173,7 +173,7 @@ static char *tomoyo_get_local_path(struct dentry *dentry, char * const buffer,
                 * Use filesystem name if filesystem does not support rename()
                 * operation.
                 */
-               if (!inode->i_op->rename)
+               if (!inode->i_op->rename && !inode->i_op->rename2)
                        goto prepend_filesystem_name;
        }
        /* Prepend device name. */
@@ -282,7 +282,8 @@ char *tomoyo_realpath_from_path(struct path *path)
                 * Get local name for filesystems without rename() operation
                 * or dentry without vfsmount.
                 */
-               if (!path->mnt || !inode->i_op->rename)
+               if (!path->mnt ||
+                   (!inode->i_op->rename && !inode->i_op->rename2))
                        pos = tomoyo_get_local_path(path->dentry, buf,
                                                    buf_len - 1);
                /* Get absolute name for the rest. */
index 051d55b05521216d31a1d011d58560744e930672..9f404e965ea26366e6ad9ec65e4946263650fd37 100644 (file)
@@ -684,7 +684,7 @@ int snd_info_card_free(struct snd_card *card)
  * snd_info_get_line - read one line from the procfs buffer
  * @buffer: the procfs buffer
  * @line: the buffer to store
- * @len: the max. buffer size - 1
+ * @len: the max. buffer size
  *
  * Reads one line from the buffer and stores the string.
  *
@@ -704,7 +704,7 @@ int snd_info_get_line(struct snd_info_buffer *buffer, char *line, int len)
                        buffer->stop = 1;
                if (c == '\n')
                        break;
-               if (len) {
+               if (len > 1) {
                        len--;
                        *line++ = c;
                }
index 4560ca0e5651ac6c515c589efa18fc8d308b1910..2c6fd80e0bd1fd0042848bdc3e68bd2734c4a0c5 100644 (file)
@@ -142,11 +142,11 @@ static struct pcm_format_data pcm_formats[(INT)SNDRV_PCM_FORMAT_LAST+1] = {
        },
        [SNDRV_PCM_FORMAT_DSD_U8] = {
                .width = 8, .phys = 8, .le = 1, .signd = 0,
-               .silence = {},
+               .silence = { 0x69 },
        },
        [SNDRV_PCM_FORMAT_DSD_U16_LE] = {
                .width = 16, .phys = 16, .le = 1, .signd = 0,
-               .silence = {},
+               .silence = { 0x69, 0x69 },
        },
        /* FIXME: the following three formats are not defined properly yet */
        [SNDRV_PCM_FORMAT_MPEG] = {
index f96bf4c7c23236a773f13a0c318ddb5b6f275977..95fc2eaf11dc0f91bcb235a2929b300c39448052 100644 (file)
@@ -507,7 +507,16 @@ static void amdtp_pull_midi(struct amdtp_stream *s,
 static void update_pcm_pointers(struct amdtp_stream *s,
                                struct snd_pcm_substream *pcm,
                                unsigned int frames)
-{      unsigned int ptr;
+{
+       unsigned int ptr;
+
+       /*
+        * In IEC 61883-6, one data block represents one event. In ALSA, one
+        * event equals to one PCM frame. But Dice has a quirk to transfer
+        * two PCM frames in one data block.
+        */
+       if (s->double_pcm_frames)
+               frames *= 2;
 
        ptr = s->pcm_buffer_pointer + frames;
        if (ptr >= pcm->runtime->buffer_size)
index d8ee7b0e938629a828571fcd45ce5da5edc02469..4823c08196ac775f150656b712dd7839b5428a29 100644 (file)
@@ -125,6 +125,7 @@ struct amdtp_stream {
        unsigned int pcm_buffer_pointer;
        unsigned int pcm_period_pointer;
        bool pointer_flush;
+       bool double_pcm_frames;
 
        struct snd_rawmidi_substream *midi[AMDTP_MAX_CHANNELS_FOR_MIDI * 8];
 
index a9a30c0161f17be87e9c79403d1c913f85ab4c86..e3a04d69c85363dfffdc6bebf5400b95cff401fa 100644 (file)
@@ -567,10 +567,14 @@ static int dice_hw_params(struct snd_pcm_substream *substream,
                return err;
 
        /*
-        * At rates above 96 kHz, pretend that the stream runs at half the
-        * actual sample rate with twice the number of channels; two samples
-        * of a channel are stored consecutively in the packet. Requires
-        * blocking mode and PCM buffer size should be aligned to SYT_INTERVAL.
+        * At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in
+        * one data block of AMDTP packet. Thus sampling transfer frequency is
+        * a half of PCM sampling frequency, i.e. PCM frames at 192.0 kHz are
+        * transferred on AMDTP packets at 96 kHz. Two successive samples of a
+        * channel are stored consecutively in the packet. This quirk is called
+        * as 'Dual Wire'.
+        * For this quirk, blocking mode is required and PCM buffer size should
+        * be aligned to SYT_INTERVAL.
         */
        channels = params_channels(hw_params);
        if (rate_index > 4) {
@@ -579,18 +583,25 @@ static int dice_hw_params(struct snd_pcm_substream *substream,
                        return err;
                }
 
-               for (i = 0; i < channels; i++) {
-                       dice->stream.pcm_positions[i * 2] = i;
-                       dice->stream.pcm_positions[i * 2 + 1] = i + channels;
-               }
-
                rate /= 2;
                channels *= 2;
+               dice->stream.double_pcm_frames = true;
+       } else {
+               dice->stream.double_pcm_frames = false;
        }
 
        mode = rate_index_to_mode(rate_index);
        amdtp_stream_set_parameters(&dice->stream, rate, channels,
                                    dice->rx_midi_ports[mode]);
+       if (rate_index > 4) {
+               channels /= 2;
+
+               for (i = 0; i < channels; i++) {
+                       dice->stream.pcm_positions[i] = i * 2;
+                       dice->stream.pcm_positions[i + channels] = i * 2 + 1;
+               }
+       }
+
        amdtp_stream_set_pcm_format(&dice->stream,
                                    params_format(hw_params));
 
index 62b8869f5a4c43737dc3e89e9cc408c535676ed2..279bc565ac7e9a01a7d0a8093041d734d31aaefe 100644 (file)
@@ -30,7 +30,7 @@
 
 #include "mpu401.h"
 
-typedef struct uart401_devc
+struct uart401_devc
 {
        int             base;
        int             irq;
@@ -41,14 +41,13 @@ typedef struct uart401_devc
        int             my_dev;
        int             share_irq;
        spinlock_t      lock;
-}
-uart401_devc;
+};
 
 #define        DATAPORT   (devc->base)
 #define        COMDPORT   (devc->base+1)
 #define        STATPORT   (devc->base+1)
 
-static int uart401_status(uart401_devc * devc)
+static int uart401_status(struct uart401_devc *devc)
 {
        return inb(STATPORT);
 }
@@ -56,17 +55,17 @@ static int uart401_status(uart401_devc * devc)
 #define input_avail(devc) (!(uart401_status(devc)&INPUT_AVAIL))
 #define output_ready(devc)     (!(uart401_status(devc)&OUTPUT_READY))
 
-static void uart401_cmd(uart401_devc * devc, unsigned char cmd)
+static void uart401_cmd(struct uart401_devc *devc, unsigned char cmd)
 {
        outb((cmd), COMDPORT);
 }
 
-static int uart401_read(uart401_devc * devc)
+static int uart401_read(struct uart401_devc *devc)
 {
        return inb(DATAPORT);
 }
 
-static void uart401_write(uart401_devc * devc, unsigned char byte)
+static void uart401_write(struct uart401_devc *devc, unsigned char byte)
 {
        outb((byte), DATAPORT);
 }
@@ -77,10 +76,10 @@ static void uart401_write(uart401_devc * devc, unsigned char byte)
 #define        MPU_RESET       0xFF
 #define        UART_MODE_ON    0x3F
 
-static int      reset_uart401(uart401_devc * devc);
-static void     enter_uart_mode(uart401_devc * devc);
+static int      reset_uart401(struct uart401_devc *devc);
+static void     enter_uart_mode(struct uart401_devc *devc);
 
-static void uart401_input_loop(uart401_devc * devc)
+static void uart401_input_loop(struct uart401_devc *devc)
 {
        int work_limit=30000;
        
@@ -99,7 +98,7 @@ static void uart401_input_loop(uart401_devc * devc)
 
 irqreturn_t uart401intr(int irq, void *dev_id)
 {
-       uart401_devc *devc = dev_id;
+       struct uart401_devc *devc = dev_id;
 
        if (devc == NULL)
        {
@@ -118,7 +117,8 @@ uart401_open(int dev, int mode,
             void            (*output) (int dev)
 )
 {
-       uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc;
+       struct uart401_devc *devc = (struct uart401_devc *)
+                                   midi_devs[dev]->devc;
 
        if (devc->opened)
                return -EBUSY;
@@ -138,7 +138,8 @@ uart401_open(int dev, int mode,
 
 static void uart401_close(int dev)
 {
-       uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc;
+       struct uart401_devc *devc = (struct uart401_devc *)
+                                   midi_devs[dev]->devc;
 
        reset_uart401(devc);
        devc->opened = 0;
@@ -148,7 +149,8 @@ static int uart401_out(int dev, unsigned char midi_byte)
 {
        int timeout;
        unsigned long flags;
-       uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc;
+       struct uart401_devc *devc = (struct uart401_devc *)
+                                   midi_devs[dev]->devc;
 
        if (devc->disabled)
                return 1;
@@ -219,7 +221,7 @@ static const struct midi_operations uart401_operations =
        .buffer_status  = uart401_buffer_status,
 };
 
-static void enter_uart_mode(uart401_devc * devc)
+static void enter_uart_mode(struct uart401_devc *devc)
 {
        int ok, timeout;
        unsigned long flags;
@@ -241,7 +243,7 @@ static void enter_uart_mode(uart401_devc * devc)
        spin_unlock_irqrestore(&devc->lock,flags);
 }
 
-static int reset_uart401(uart401_devc * devc)
+static int reset_uart401(struct uart401_devc *devc)
 {
        int ok, timeout, n;
 
@@ -285,7 +287,7 @@ static int reset_uart401(uart401_devc * devc)
 
 int probe_uart401(struct address_info *hw_config, struct module *owner)
 {
-       uart401_devc *devc;
+       struct uart401_devc *devc;
        char *name = "MPU-401 (UART) MIDI";
        int ok = 0;
        unsigned long flags;
@@ -300,7 +302,7 @@ int probe_uart401(struct address_info *hw_config, struct module *owner)
                return 0;
        }
 
-       devc = kmalloc(sizeof(uart401_devc), GFP_KERNEL);
+       devc = kmalloc(sizeof(struct uart401_devc), GFP_KERNEL);
        if (!devc) {
                printk(KERN_WARNING "uart401: Can't allocate memory\n");
                goto cleanup_region;
@@ -392,7 +394,7 @@ cleanup_region:
 
 void unload_uart401(struct address_info *hw_config)
 {
-       uart401_devc *devc;
+       struct uart401_devc *devc;
        int n=hw_config->slots[4];
        
        /* Not set up */
index 672af8b56542ddf8e04639dca07959dcb1d1ac79..b36ea47527e87f567cd5c97ee7b9d3297676f092 100644 (file)
@@ -92,7 +92,7 @@ static unsigned short levels[SOUND_MIXER_NRDEVICES] = {
        0x0000          /* Monitor               */
 };
 
-typedef struct {
+struct wavnc_info {
        struct address_info  hw;        /* hardware */
        char            *chip_name;
 
@@ -119,7 +119,7 @@ typedef struct {
        unsigned int    line_mute_state :1;/* set by ioctl or autoselect */
        unsigned int    use_slider      :1;/* use slider setting for o/p vol */
 #endif
-} wavnc_info;
+};
 
 /*
  * This is the implementation specific mixer information.
@@ -129,29 +129,30 @@ struct waveartist_mixer_info {
        unsigned int    recording_devs;    /* Recordable devies */
        unsigned int    stereo_devs;       /* Stereo devices    */
 
-       unsigned int    (*select_input)(wavnc_info *, unsigned int,
+       unsigned int    (*select_input)(struct wavnc_info *, unsigned int,
                                        unsigned char *, unsigned char *);
-       int             (*decode_mixer)(wavnc_info *, int,
+       int             (*decode_mixer)(struct wavnc_info *, int,
                                        unsigned char, unsigned char);
-       int             (*get_mixer)(wavnc_info *, int);
+       int             (*get_mixer)(struct wavnc_info *, int);
 };
 
-typedef struct wavnc_port_info {
+struct wavnc_port_info {
        int             open_mode;
        int             speed;
        int             channels;
        int             audio_format;
-} wavnc_port_info;
+};
 
 static int             nr_waveartist_devs;
-static wavnc_info      adev_info[MAX_AUDIO_DEV];
+static struct wavnc_info       adev_info[MAX_AUDIO_DEV];
 static DEFINE_SPINLOCK(waveartist_lock);
 
 #ifndef CONFIG_ARCH_NETWINDER
 #define machine_is_netwinder() 0
 #else
 static struct timer_list vnc_timer;
-static void vnc_configure_mixer(wavnc_info *devc, unsigned int input_mask);
+static void vnc_configure_mixer(struct wavnc_info *devc,
+                               unsigned int input_mask);
 static int vnc_private_ioctl(int dev, unsigned int cmd, int __user *arg);
 static void vnc_slider_tick(unsigned long data);
 #endif
@@ -169,7 +170,7 @@ waveartist_set_ctlr(struct address_info *hw, unsigned char clear, unsigned char
 /* Toggle IRQ acknowledge line
  */
 static inline void
-waveartist_iack(wavnc_info *devc)
+waveartist_iack(struct wavnc_info *devc)
 {
        unsigned int ctlr_port = devc->hw.io_base + CTLR;
        int old_ctlr;
@@ -188,7 +189,7 @@ waveartist_sleep(int timeout_ms)
 }
 
 static int
-waveartist_reset(wavnc_info *devc)
+waveartist_reset(struct wavnc_info *devc)
 {
        struct address_info *hw = &devc->hw;
        unsigned int timeout, res = -1;
@@ -223,7 +224,7 @@ waveartist_reset(wavnc_info *devc)
  * and can send or receive multiple words.
  */
 static int
-waveartist_cmd(wavnc_info *devc,
+waveartist_cmd(struct wavnc_info *devc,
                int nr_cmd, unsigned int *cmd,
                int nr_resp, unsigned int *resp)
 {
@@ -299,7 +300,7 @@ waveartist_cmd(wavnc_info *devc,
  * Send one command word
  */
 static inline int
-waveartist_cmd1(wavnc_info *devc, unsigned int cmd)
+waveartist_cmd1(struct wavnc_info *devc, unsigned int cmd)
 {
        return waveartist_cmd(devc, 1, &cmd, 0, NULL);
 }
@@ -308,7 +309,7 @@ waveartist_cmd1(wavnc_info *devc, unsigned int cmd)
  * Send one command, receive one word
  */
 static inline unsigned int
-waveartist_cmd1_r(wavnc_info *devc, unsigned int cmd)
+waveartist_cmd1_r(struct wavnc_info *devc, unsigned int cmd)
 {
        unsigned int ret;
 
@@ -322,7 +323,7 @@ waveartist_cmd1_r(wavnc_info *devc, unsigned int cmd)
  * word (and throw it away)
  */
 static inline int
-waveartist_cmd2(wavnc_info *devc, unsigned int cmd, unsigned int arg)
+waveartist_cmd2(struct wavnc_info *devc, unsigned int cmd, unsigned int arg)
 {
        unsigned int vals[2];
 
@@ -336,7 +337,7 @@ waveartist_cmd2(wavnc_info *devc, unsigned int cmd, unsigned int arg)
  * Send a triple command
  */
 static inline int
-waveartist_cmd3(wavnc_info *devc, unsigned int cmd,
+waveartist_cmd3(struct wavnc_info *devc, unsigned int cmd,
                unsigned int arg1, unsigned int arg2)
 {
        unsigned int vals[3];
@@ -349,7 +350,7 @@ waveartist_cmd3(wavnc_info *devc, unsigned int cmd,
 }
 
 static int
-waveartist_getrev(wavnc_info *devc, char *rev)
+waveartist_getrev(struct wavnc_info *devc, char *rev)
 {
        unsigned int temp[2];
        unsigned int cmd = WACMD_GETREV;
@@ -371,15 +372,15 @@ static void waveartist_trigger(int dev, int state);
 static int
 waveartist_open(int dev, int mode)
 {
-       wavnc_info      *devc;
-       wavnc_port_info *portc;
+       struct wavnc_info       *devc;
+       struct wavnc_port_info  *portc;
        unsigned long   flags;
 
        if (dev < 0 || dev >= num_audiodevs)
                return -ENXIO;
 
-       devc  = (wavnc_info *) audio_devs[dev]->devc;
-       portc = (wavnc_port_info *) audio_devs[dev]->portc;
+       devc  = (struct wavnc_info *) audio_devs[dev]->devc;
+       portc = (struct wavnc_port_info *) audio_devs[dev]->portc;
 
        spin_lock_irqsave(&waveartist_lock, flags);
        if (portc->open_mode || (devc->open_mode & mode)) {
@@ -404,8 +405,10 @@ waveartist_open(int dev, int mode)
 static void
 waveartist_close(int dev)
 {
-       wavnc_info      *devc = (wavnc_info *) audio_devs[dev]->devc;
-       wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc;
+       struct wavnc_info       *devc = (struct wavnc_info *)
+                                       audio_devs[dev]->devc;
+       struct wavnc_port_info  *portc = (struct wavnc_port_info *)
+                                        audio_devs[dev]->portc;
        unsigned long   flags;
 
        spin_lock_irqsave(&waveartist_lock, flags);
@@ -422,8 +425,10 @@ waveartist_close(int dev)
 static void
 waveartist_output_block(int dev, unsigned long buf, int __count, int intrflag)
 {
-       wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc;
-       wavnc_info      *devc = (wavnc_info *) audio_devs[dev]->devc;
+       struct wavnc_port_info  *portc = (struct wavnc_port_info *)
+                                        audio_devs[dev]->portc;
+       struct wavnc_info       *devc = (struct wavnc_info *)
+                                       audio_devs[dev]->devc;
        unsigned long   flags;
        unsigned int    count = __count; 
 
@@ -467,8 +472,10 @@ waveartist_output_block(int dev, unsigned long buf, int __count, int intrflag)
 static void
 waveartist_start_input(int dev, unsigned long buf, int __count, int intrflag)
 {
-       wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc;
-       wavnc_info      *devc = (wavnc_info *) audio_devs[dev]->devc;
+       struct wavnc_port_info *portc = (struct wavnc_port_info *)
+                                       audio_devs[dev]->portc;
+       struct wavnc_info       *devc = (struct wavnc_info *)
+                                       audio_devs[dev]->devc;
        unsigned long   flags;
        unsigned int    count = __count;
 
@@ -514,7 +521,7 @@ waveartist_ioctl(int dev, unsigned int cmd, void __user * arg)
 }
 
 static unsigned int
-waveartist_get_speed(wavnc_port_info *portc)
+waveartist_get_speed(struct wavnc_port_info *portc)
 {
        unsigned int speed;
 
@@ -542,7 +549,7 @@ waveartist_get_speed(wavnc_port_info *portc)
 }
 
 static unsigned int
-waveartist_get_bits(wavnc_port_info *portc)
+waveartist_get_bits(struct wavnc_port_info *portc)
 {
        unsigned int bits;
 
@@ -560,8 +567,10 @@ static int
 waveartist_prepare_for_input(int dev, int bsize, int bcount)
 {
        unsigned long   flags;
-       wavnc_info      *devc = (wavnc_info *) audio_devs[dev]->devc;
-       wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc;
+       struct wavnc_info       *devc = (struct wavnc_info *)
+                                       audio_devs[dev]->devc;
+       struct wavnc_port_info  *portc = (struct wavnc_port_info *)
+                                        audio_devs[dev]->portc;
        unsigned int    speed, bits;
 
        if (devc->audio_mode)
@@ -615,8 +624,10 @@ static int
 waveartist_prepare_for_output(int dev, int bsize, int bcount)
 {
        unsigned long   flags;
-       wavnc_info      *devc = (wavnc_info *) audio_devs[dev]->devc;
-       wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc;
+       struct wavnc_info       *devc = (struct wavnc_info *)
+                                       audio_devs[dev]->devc;
+       struct wavnc_port_info  *portc = (struct wavnc_port_info *)
+                                        audio_devs[dev]->portc;
        unsigned int    speed, bits;
 
        /*
@@ -660,8 +671,9 @@ waveartist_prepare_for_output(int dev, int bsize, int bcount)
 static void
 waveartist_halt(int dev)
 {
-       wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc;
-       wavnc_info      *devc;
+       struct wavnc_port_info  *portc = (struct wavnc_port_info *)
+                                        audio_devs[dev]->portc;
+       struct wavnc_info       *devc;
 
        if (portc->open_mode & OPEN_WRITE)
                waveartist_halt_output(dev);
@@ -669,14 +681,15 @@ waveartist_halt(int dev)
        if (portc->open_mode & OPEN_READ)
                waveartist_halt_input(dev);
 
-       devc = (wavnc_info *) audio_devs[dev]->devc;
+       devc = (struct wavnc_info *) audio_devs[dev]->devc;
        devc->audio_mode = 0;
 }
 
 static void
 waveartist_halt_input(int dev)
 {
-       wavnc_info      *devc = (wavnc_info *) audio_devs[dev]->devc;
+       struct wavnc_info       *devc = (struct wavnc_info *)
+                                       audio_devs[dev]->devc;
        unsigned long   flags;
 
        spin_lock_irqsave(&waveartist_lock, flags);
@@ -703,7 +716,8 @@ waveartist_halt_input(int dev)
 static void
 waveartist_halt_output(int dev)
 {
-       wavnc_info      *devc = (wavnc_info *) audio_devs[dev]->devc;
+       struct wavnc_info       *devc = (struct wavnc_info *)
+                                       audio_devs[dev]->devc;
        unsigned long   flags;
 
        spin_lock_irqsave(&waveartist_lock, flags);
@@ -727,8 +741,10 @@ waveartist_halt_output(int dev)
 static void
 waveartist_trigger(int dev, int state)
 {
-       wavnc_info      *devc = (wavnc_info *) audio_devs[dev]->devc;
-       wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc;
+       struct wavnc_info       *devc = (struct wavnc_info *)
+                                       audio_devs[dev]->devc;
+       struct wavnc_port_info  *portc = (struct wavnc_port_info *)
+                                        audio_devs[dev]->portc;
        unsigned long   flags;
 
        if (debug_flg & DEBUG_TRIGGER) {
@@ -764,7 +780,8 @@ waveartist_trigger(int dev, int state)
 static int
 waveartist_set_speed(int dev, int arg)
 {
-       wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc;
+       struct wavnc_port_info *portc = (struct wavnc_port_info *)
+                                       audio_devs[dev]->portc;
 
        if (arg <= 0)
                return portc->speed;
@@ -782,7 +799,8 @@ waveartist_set_speed(int dev, int arg)
 static short
 waveartist_set_channels(int dev, short arg)
 {
-       wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc;
+       struct wavnc_port_info *portc = (struct wavnc_port_info *)
+                                       audio_devs[dev]->portc;
 
        if (arg != 1 && arg != 2)
                return portc->channels;
@@ -794,7 +812,8 @@ waveartist_set_channels(int dev, short arg)
 static unsigned int
 waveartist_set_bits(int dev, unsigned int arg)
 {
-       wavnc_port_info *portc = (wavnc_port_info *) audio_devs[dev]->portc;
+       struct wavnc_port_info *portc = (struct wavnc_port_info *)
+                                       audio_devs[dev]->portc;
 
        if (arg == 0)
                return portc->audio_format;
@@ -829,7 +848,7 @@ static struct audio_driver waveartist_audio_driver = {
 static irqreturn_t
 waveartist_intr(int irq, void *dev_id)
 {
-       wavnc_info *devc = dev_id;
+       struct wavnc_info *devc = dev_id;
        int        irqstatus, status;
 
        spin_lock(&waveartist_lock);
@@ -912,7 +931,7 @@ static const struct mix_ent mix_devs[SOUND_MIXER_NRDEVICES] = {
 };
 
 static void
-waveartist_mixer_update(wavnc_info *devc, int whichDev)
+waveartist_mixer_update(struct wavnc_info *devc, int whichDev)
 {
        unsigned int lev_left, lev_right;
 
@@ -973,7 +992,8 @@ waveartist_mixer_update(wavnc_info *devc, int whichDev)
  * relevant *_select_input function has done that for us.
  */
 static void
-waveartist_set_adc_mux(wavnc_info *devc, char left_dev, char right_dev)
+waveartist_set_adc_mux(struct wavnc_info *devc, char left_dev,
+                      char right_dev)
 {
        unsigned int reg_08, reg_09;
 
@@ -996,7 +1016,7 @@ waveartist_set_adc_mux(wavnc_info *devc, char left_dev, char right_dev)
  *  SOUND_MASK_MIC     Mic             Microphone
  */
 static unsigned int
-waveartist_select_input(wavnc_info *devc, unsigned int recmask,
+waveartist_select_input(struct wavnc_info *devc, unsigned int recmask,
                        unsigned char *dev_l, unsigned char *dev_r)
 {
        unsigned int recdev = ADC_MUX_NONE;
@@ -1024,7 +1044,8 @@ waveartist_select_input(wavnc_info *devc, unsigned int recmask,
 }
 
 static int
-waveartist_decode_mixer(wavnc_info *devc, int dev, unsigned char lev_l,
+waveartist_decode_mixer(struct wavnc_info *devc, int dev,
+                       unsigned char lev_l,
                        unsigned char lev_r)
 {
        switch (dev) {
@@ -1050,7 +1071,7 @@ waveartist_decode_mixer(wavnc_info *devc, int dev, unsigned char lev_l,
        return dev;
 }
 
-static int waveartist_get_mixer(wavnc_info *devc, int dev)
+static int waveartist_get_mixer(struct wavnc_info *devc, int dev)
 {
        return devc->levels[dev];
 }
@@ -1068,7 +1089,7 @@ static const struct waveartist_mixer_info waveartist_mixer = {
 };
 
 static void
-waveartist_set_recmask(wavnc_info *devc, unsigned int recmask)
+waveartist_set_recmask(struct wavnc_info *devc, unsigned int recmask)
 {
        unsigned char dev_l, dev_r;
 
@@ -1092,7 +1113,7 @@ waveartist_set_recmask(wavnc_info *devc, unsigned int recmask)
 }
 
 static int
-waveartist_set_mixer(wavnc_info *devc, int dev, unsigned int level)
+waveartist_set_mixer(struct wavnc_info *devc, int dev, unsigned int level)
 {
        unsigned int lev_left  = level & 0x00ff;
        unsigned int lev_right = (level & 0xff00) >> 8;
@@ -1120,7 +1141,7 @@ waveartist_set_mixer(wavnc_info *devc, int dev, unsigned int level)
 static int
 waveartist_mixer_ioctl(int dev, unsigned int cmd, void __user * arg)
 {
-       wavnc_info *devc = (wavnc_info *)audio_devs[dev]->devc;
+       struct wavnc_info *devc = (struct wavnc_info *)audio_devs[dev]->devc;
        int ret = 0, val, nr;
 
        /*
@@ -1204,7 +1225,7 @@ static struct mixer_operations waveartist_mixer_operations =
 };
 
 static void
-waveartist_mixer_reset(wavnc_info *devc)
+waveartist_mixer_reset(struct wavnc_info *devc)
 {
        int i;
 
@@ -1241,9 +1262,9 @@ waveartist_mixer_reset(wavnc_info *devc)
                waveartist_mixer_update(devc, i);
 }
 
-static int __init waveartist_init(wavnc_info *devc)
+static int __init waveartist_init(struct wavnc_info *devc)
 {
-       wavnc_port_info *portc;
+       struct wavnc_port_info *portc;
        char rev[3], dev_name[64];
        int my_dev;
 
@@ -1261,7 +1282,7 @@ static int __init waveartist_init(wavnc_info *devc)
        conf_printf2(dev_name, devc->hw.io_base, devc->hw.irq,
                     devc->hw.dma, devc->hw.dma2);
 
-       portc = kzalloc(sizeof(wavnc_port_info), GFP_KERNEL);
+       portc = kzalloc(sizeof(struct wavnc_port_info), GFP_KERNEL);
        if (portc == NULL)
                goto nomem;
 
@@ -1330,7 +1351,7 @@ nomem:
 
 static int __init probe_waveartist(struct address_info *hw_config)
 {
-       wavnc_info *devc = &adev_info[nr_waveartist_devs];
+       struct wavnc_info *devc = &adev_info[nr_waveartist_devs];
 
        if (nr_waveartist_devs >= MAX_AUDIO_DEV) {
                printk(KERN_WARNING "waveartist: too many audio devices\n");
@@ -1367,7 +1388,7 @@ static int __init probe_waveartist(struct address_info *hw_config)
 static void __init
 attach_waveartist(struct address_info *hw, const struct waveartist_mixer_info *mix)
 {
-       wavnc_info *devc = &adev_info[nr_waveartist_devs];
+       struct wavnc_info *devc = &adev_info[nr_waveartist_devs];
 
        /*
         * NOTE! If irq < 0, there is another driver which has allocated the
@@ -1410,7 +1431,7 @@ attach_waveartist(struct address_info *hw, const struct waveartist_mixer_info *m
 
 static void __exit unload_waveartist(struct address_info *hw)
 {
-       wavnc_info *devc = NULL;
+       struct wavnc_info *devc = NULL;
        int i;
 
        for (i = 0; i < nr_waveartist_devs; i++)
@@ -1478,7 +1499,7 @@ static void __exit unload_waveartist(struct address_info *hw)
 #define VNC_DISABLE_AUTOSWITCH 0x80
 
 static inline void
-vnc_mute_spkr(wavnc_info *devc)
+vnc_mute_spkr(struct wavnc_info *devc)
 {
        unsigned long flags;
 
@@ -1488,7 +1509,7 @@ vnc_mute_spkr(wavnc_info *devc)
 }
 
 static void
-vnc_mute_lout(wavnc_info *devc)
+vnc_mute_lout(struct wavnc_info *devc)
 {
        unsigned int left, right;
 
@@ -1507,7 +1528,7 @@ vnc_mute_lout(wavnc_info *devc)
 }
 
 static int
-vnc_volume_slider(wavnc_info *devc)
+vnc_volume_slider(struct wavnc_info *devc)
 {
        static signed int old_slider_volume;
        unsigned long flags;
@@ -1567,7 +1588,7 @@ vnc_volume_slider(wavnc_info *devc)
  *  SOUND_MASK_MIC     Right Mic       Builtin microphone
  */
 static unsigned int
-netwinder_select_input(wavnc_info *devc, unsigned int recmask,
+netwinder_select_input(struct wavnc_info *devc, unsigned int recmask,
                       unsigned char *dev_l, unsigned char *dev_r)
 {
        unsigned int recdev_l = ADC_MUX_NONE, recdev_r = ADC_MUX_NONE;
@@ -1604,7 +1625,7 @@ netwinder_select_input(wavnc_info *devc, unsigned int recmask,
 }
 
 static int
-netwinder_decode_mixer(wavnc_info *devc, int dev, unsigned char lev_l,
+netwinder_decode_mixer(struct wavnc_info *devc, int dev, unsigned char lev_l,
                       unsigned char lev_r)
 {
        switch (dev) {
@@ -1643,7 +1664,7 @@ netwinder_decode_mixer(wavnc_info *devc, int dev, unsigned char lev_l,
        return dev;
 }
 
-static int netwinder_get_mixer(wavnc_info *devc, int dev)
+static int netwinder_get_mixer(struct wavnc_info *devc, int dev)
 {
        int levels;
 
@@ -1703,7 +1724,7 @@ static const struct waveartist_mixer_info netwinder_mixer = {
 };
 
 static void
-vnc_configure_mixer(wavnc_info *devc, unsigned int recmask)
+vnc_configure_mixer(struct wavnc_info *devc, unsigned int recmask)
 {
        if (!devc->no_autoselect) {
                if (devc->handset_detect) {
@@ -1729,7 +1750,7 @@ vnc_configure_mixer(wavnc_info *devc, unsigned int recmask)
 }
 
 static int
-vnc_slider(wavnc_info *devc)
+vnc_slider(struct wavnc_info *devc)
 {
        signed int slider_volume;
        unsigned int temp, old_hs, old_td;
@@ -1795,7 +1816,7 @@ vnc_slider_tick(unsigned long data)
 static int
 vnc_private_ioctl(int dev, unsigned int cmd, int __user * arg)
 {
-       wavnc_info *devc = (wavnc_info *)audio_devs[dev]->devc;
+       struct wavnc_info *devc = (struct wavnc_info *)audio_devs[dev]->devc;
        int val;
 
        switch (cmd) {
index f2e34e3f27eef6336d5798ae634b5f5ecc8aed70..5851249f11d912a318af26b9fc2ac6d933efe492 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 #ifndef CT20K1REG_H
-#define CT20k1REG_H
+#define CT20K1REG_H
 
 /* 20k1 registers */
 #define        DSPXRAM_START                   0x000000
 #define I2SD_R    0x19L
 
 #endif /* CT20K1REG_H */
-
-
index 07e760937d3c0fc83bc7214f775a3a621173bdc9..8371274aa8116b90fe14dc03c712aac48b2c2897 100644 (file)
@@ -20,7 +20,7 @@
  */
 
 #ifndef __CA0132_REGS_H
-#define __CA0312_REGS_H
+#define __CA0132_REGS_H
 
 #define DSP_CHIP_OFFSET                0x100000
 #define DSP_DBGCNTL_MODULE_OFFSET      0xE30
index 5db1948699d88c37ba02735fc949c6642f474914..aa302fb03fc5bfe582b2f27dd3616a5b4ef039aa 100644 (file)
@@ -265,6 +265,7 @@ enum {
        AZX_DRIVER_TERA,
        AZX_DRIVER_CTX,
        AZX_DRIVER_CTHDA,
+       AZX_DRIVER_CMEDIA,
        AZX_DRIVER_GENERIC,
        AZX_NUM_DRIVERS, /* keep this as last entry */
 };
@@ -330,6 +331,7 @@ static char *driver_short_names[] = {
        [AZX_DRIVER_TERA] = "HDA Teradici", 
        [AZX_DRIVER_CTX] = "HDA Creative", 
        [AZX_DRIVER_CTHDA] = "HDA Creative",
+       [AZX_DRIVER_CMEDIA] = "HDA C-Media",
        [AZX_DRIVER_GENERIC] = "HD-Audio Generic",
 };
 
@@ -1373,6 +1375,7 @@ static void azx_check_snoop_available(struct azx *chip)
                snoop = false;
                break;
        case AZX_DRIVER_CTHDA:
+       case AZX_DRIVER_CMEDIA:
                snoop = false;
                break;
        }
@@ -2154,6 +2157,10 @@ static const struct pci_device_id azx_ids[] = {
          .driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND |
          AZX_DCAPS_RIRB_PRE_DELAY | AZX_DCAPS_POSFIX_LPIB },
 #endif
+       /* CM8888 */
+       { PCI_DEVICE(0x13f6, 0x5011),
+         .driver_data = AZX_DRIVER_CMEDIA |
+         AZX_DCAPS_NO_MSI | AZX_DCAPS_POSFIX_LPIB },
        /* Vortex86MX */
        { PCI_DEVICE(0x17f3, 0x3010), .driver_data = AZX_DRIVER_GENERIC },
        /* VMware HDAudio */
index 4f3aba78f720ceb6a7bf97470e5bd5e72eea4a89..5d8455e2dacd709c308d215a44155134e15319cd 100644 (file)
@@ -4376,6 +4376,9 @@ static void ca0132_download_dsp(struct hda_codec *codec)
        return; /* NOP */
 #endif
 
+       if (spec->dsp_state == DSP_DOWNLOAD_FAILED)
+               return; /* don't retry failures */
+
        chipio_enable_clocks(codec);
        spec->dsp_state = DSP_DOWNLOADING;
        if (!ca0132_download_dsp_images(codec))
@@ -4552,7 +4555,8 @@ static int ca0132_init(struct hda_codec *codec)
        struct auto_pin_cfg *cfg = &spec->autocfg;
        int i;
 
-       spec->dsp_state = DSP_DOWNLOAD_INIT;
+       if (spec->dsp_state != DSP_DOWNLOAD_FAILED)
+               spec->dsp_state = DSP_DOWNLOAD_INIT;
        spec->curr_chip_addx = INVALID_CHIP_ADDRESS;
 
        snd_hda_power_up(codec);
@@ -4663,6 +4667,7 @@ static int patch_ca0132(struct hda_codec *codec)
        codec->spec = spec;
        spec->codec = codec;
 
+       spec->dsp_state = DSP_DOWNLOAD_INIT;
        spec->num_mixers = 1;
        spec->mixers[0] = ca0132_mixer;
 
index ed3d133ffbb6567ccf2d76f13e3bcc3fcfde418b..c895a8f211922415b1498a2092772149d9ab13c7 100644 (file)
@@ -75,15 +75,62 @@ static int patch_cmi9880(struct hda_codec *codec)
        return err;
 }
 
+static int patch_cmi8888(struct hda_codec *codec)
+{
+       struct cmi_spec *spec;
+       struct auto_pin_cfg *cfg;
+       int err;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (!spec)
+               return -ENOMEM;
+
+       codec->spec = spec;
+       cfg = &spec->gen.autocfg;
+       snd_hda_gen_spec_init(&spec->gen);
+
+       /* mask NID 0x10 from the playback volume selection;
+        * it's a headphone boost volume handled manually below
+        */
+       spec->gen.out_vol_mask = (1ULL << 0x10);
+
+       err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
+       if (err < 0)
+               goto error;
+       err = snd_hda_gen_parse_auto_config(codec, cfg);
+       if (err < 0)
+               goto error;
+
+       if (get_defcfg_device(snd_hda_codec_get_pincfg(codec, 0x10)) ==
+           AC_JACK_HP_OUT) {
+               static const struct snd_kcontrol_new amp_kctl =
+                       HDA_CODEC_VOLUME("Headphone Amp Playback Volume",
+                                        0x10, 0, HDA_OUTPUT);
+               if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &amp_kctl)) {
+                       err = -ENOMEM;
+                       goto error;
+               }
+       }
+
+       codec->patch_ops = cmi_auto_patch_ops;
+       return 0;
+
+ error:
+       snd_hda_gen_free(codec);
+       return err;
+}
+
 /*
  * patch entries
  */
 static const struct hda_codec_preset snd_hda_preset_cmedia[] = {
+       { .id = 0x13f68888, .name = "CMI8888", .patch = patch_cmi8888 },
        { .id = 0x13f69880, .name = "CMI9880", .patch = patch_cmi9880 },
        { .id = 0x434d4980, .name = "CMI9880", .patch = patch_cmi9880 },
        {} /* terminator */
 };
 
+MODULE_ALIAS("snd-hda-codec-id:13f68888");
 MODULE_ALIAS("snd-hda-codec-id:13f69880");
 MODULE_ALIAS("snd-hda-codec-id:434d4980");
 
index 7627a69ca6d78313a36bb4c93eae37b158f2ad67..6e5d0cb4e3d737ff43f0eb63e298de817552d224 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/module.h>
 #include <sound/core.h>
 #include <sound/jack.h>
+#include <sound/tlv.h>
 
 #include "hda_codec.h"
 #include "hda_local.h"
@@ -216,6 +217,7 @@ enum {
        CXT_FIXUP_HEADPHONE_MIC_PIN,
        CXT_FIXUP_HEADPHONE_MIC,
        CXT_FIXUP_GPIO1,
+       CXT_FIXUP_ASPIRE_DMIC,
        CXT_FIXUP_THINKPAD_ACPI,
        CXT_FIXUP_OLPC_XO,
        CXT_FIXUP_CAP_MIX_AMP,
@@ -663,6 +665,12 @@ static const struct hda_fixup cxt_fixups[] = {
                        { }
                },
        },
+       [CXT_FIXUP_ASPIRE_DMIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cxt_fixup_stereo_dmic,
+               .chained = true,
+               .chain_id = CXT_FIXUP_GPIO1,
+       },
        [CXT_FIXUP_THINKPAD_ACPI] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = hda_fixup_thinkpad_acpi,
@@ -743,7 +751,7 @@ static const struct hda_model_fixup cxt5051_fixup_models[] = {
 
 static const struct snd_pci_quirk cxt5066_fixups[] = {
        SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC),
-       SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT_FIXUP_GPIO1),
+       SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT_FIXUP_ASPIRE_DMIC),
        SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN),
        SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT_FIXUP_OLPC_XO),
        SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410),
@@ -859,6 +867,11 @@ static int patch_conexant_auto(struct hda_codec *codec)
        if (err < 0)
                goto error;
 
+       if (codec->vendor_id == 0x14f15051) {
+               /* minimum value is actually mute */
+               spec->gen.vmaster_tlv[3] |= TLV_DB_SCALE_MUTE;
+       }
+
        codec->patch_ops = cx_auto_patch_ops;
 
        /* Some laptops with Conexant chips show stalls in S3 resume,
index 36badba2dcec8bde02b67229e4bb8bcd1a3ad3fb..99d7d7fecaad09934090eb6575cfb43131f2dfb4 100644 (file)
@@ -50,6 +50,8 @@ MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info");
 #define is_haswell_plus(codec) (is_haswell(codec) || is_broadwell(codec))
 
 #define is_valleyview(codec) ((codec)->vendor_id == 0x80862882)
+#define is_cherryview(codec) ((codec)->vendor_id == 0x80862883)
+#define is_valleyview_plus(codec) (is_valleyview(codec) || is_cherryview(codec))
 
 struct hdmi_spec_per_cvt {
        hda_nid_t cvt_nid;
@@ -1459,7 +1461,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
                            mux_idx);
 
        /* configure unused pins to choose other converters */
-       if (is_haswell_plus(codec) || is_valleyview(codec))
+       if (is_haswell_plus(codec) || is_valleyview_plus(codec))
                intel_not_share_assigned_cvt(codec, per_pin->pin_nid, mux_idx);
 
        snd_hda_spdif_ctls_assign(codec, pin_idx, per_cvt->cvt_nid);
@@ -1598,7 +1600,8 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
                 *   and this can make HW reset converter selection on a pin.
                 */
                if (eld->eld_valid && !old_eld_valid && per_pin->setup) {
-                       if (is_haswell_plus(codec) || is_valleyview(codec)) {
+                       if (is_haswell_plus(codec) ||
+                               is_valleyview_plus(codec)) {
                                intel_verify_pin_cvt_connect(codec, per_pin);
                                intel_not_share_assigned_cvt(codec, pin_nid,
                                                        per_pin->mux_idx);
@@ -1779,7 +1782,7 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
        bool non_pcm;
        int pinctl;
 
-       if (is_haswell_plus(codec) || is_valleyview(codec)) {
+       if (is_haswell_plus(codec) || is_valleyview_plus(codec)) {
                /* Verify pin:cvt selections to avoid silent audio after S3.
                 * After S3, the audio driver restores pin:cvt selections
                 * but this can happen before gfx is ready and such selection
@@ -2330,9 +2333,8 @@ static int patch_generic_hdmi(struct hda_codec *codec)
                intel_haswell_fixup_enable_dp12(codec);
        }
 
-       if (is_haswell(codec) || is_valleyview(codec)) {
+       if (is_haswell_plus(codec) || is_valleyview_plus(codec))
                codec->depop_delay = 0;
-       }
 
        if (hdmi_parse_codec(codec) < 0) {
                codec->spec = NULL;
index 654c8f16d150cc8f8763edc5b26c75c6cfc879a6..1ba22fb527c288b751d3064e041759e881013605 100644 (file)
@@ -181,6 +181,8 @@ static void alc_fix_pll(struct hda_codec *codec)
                            spec->pll_coef_idx);
        val = snd_hda_codec_read(codec, spec->pll_nid, 0,
                                 AC_VERB_GET_PROC_COEF, 0);
+       if (val == -1)
+               return;
        snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
                            spec->pll_coef_idx);
        snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF,
@@ -326,6 +328,7 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type)
                case 0x10ec0885:
                case 0x10ec0887:
                /*case 0x10ec0889:*/ /* this causes an SPDIF problem */
+               case 0x10ec0900:
                        alc889_coef_init(codec);
                        break;
                case 0x10ec0888:
@@ -2348,6 +2351,7 @@ static int patch_alc882(struct hda_codec *codec)
        switch (codec->vendor_id) {
        case 0x10ec0882:
        case 0x10ec0885:
+       case 0x10ec0900:
                break;
        default:
                /* ALC883 and variants */
@@ -2782,9 +2786,32 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
        return alc_parse_auto_config(codec, alc269_ignore, ssids);
 }
 
+static int find_ext_mic_pin(struct hda_codec *codec);
+
+static void alc286_shutup(struct hda_codec *codec)
+{
+       int i;
+       int mic_pin = find_ext_mic_pin(codec);
+       /* don't shut up pins when unloading the driver; otherwise it breaks
+        * the default pin setup at the next load of the driver
+        */
+       if (codec->bus->shutdown)
+               return;
+       for (i = 0; i < codec->init_pins.used; i++) {
+               struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i);
+               /* use read here for syncing after issuing each verb */
+               if (pin->nid != mic_pin)
+                       snd_hda_codec_read(codec, pin->nid, 0,
+                                       AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
+       }
+       codec->pins_shutup = 1;
+}
+
 static void alc269vb_toggle_power_output(struct hda_codec *codec, int power_up)
 {
        int val = alc_read_coef_idx(codec, 0x04);
+       if (val == -1)
+               return;
        if (power_up)
                val |= 1 << 11;
        else
@@ -3243,6 +3270,15 @@ static int alc269_resume(struct hda_codec *codec)
        snd_hda_codec_resume_cache(codec);
        alc_inv_dmic_sync(codec, true);
        hda_call_check_power_status(codec, 0x01);
+
+       /* on some machine, the BIOS will clear the codec gpio data when enter
+        * suspend, and won't restore the data after resume, so we restore it
+        * in the driver.
+        */
+       if (spec->gpio_led)
+               snd_hda_codec_write(codec, codec->afg, 0, AC_VERB_SET_GPIO_DATA,
+                           spec->gpio_led);
+
        if (spec->has_alc5505_dsp)
                alc5505_dsp_resume(codec);
 
@@ -4072,7 +4108,7 @@ static unsigned int alc_power_filter_xps13(struct hda_codec *codec,
 
        /* Avoid pop noises when headphones are plugged in */
        if (spec->gen.hp_jack_present)
-               if (nid == codec->afg || nid == 0x02)
+               if (nid == codec->afg || nid == 0x02 || nid == 0x15)
                        return AC_PWRST_D0;
        return power_state;
 }
@@ -4082,8 +4118,19 @@ static void alc_fixup_dell_xps13(struct hda_codec *codec,
 {
        if (action == HDA_FIXUP_ACT_PROBE) {
                struct alc_spec *spec = codec->spec;
+               struct hda_input_mux *imux = &spec->gen.input_mux;
+               int i;
+
                spec->shutup = alc_no_shutup;
                codec->power_filter = alc_power_filter_xps13;
+
+               /* Make the internal mic the default input source. */
+               for (i = 0; i < imux->num_items; i++) {
+                       if (spec->gen.imux_pins[i] == 0x12) {
+                               spec->gen.cur_mux[0] = i;
+                               break;
+                       }
+               }
        }
 }
 
@@ -4363,6 +4410,7 @@ enum {
        ALC292_FIXUP_TPT440_DOCK,
        ALC283_FIXUP_BXBT2807_MIC,
        ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED,
+       ALC282_FIXUP_ASPIRE_V5_PINS,
 };
 
 static const struct hda_fixup alc269_fixups[] = {
@@ -4810,6 +4858,22 @@ static const struct hda_fixup alc269_fixups[] = {
                .chained_before = true,
                .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE
        },
+       [ALC282_FIXUP_ASPIRE_V5_PINS] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x12, 0x90a60130 },
+                       { 0x14, 0x90170110 },
+                       { 0x17, 0x40000008 },
+                       { 0x18, 0x411111f0 },
+                       { 0x19, 0x411111f0 },
+                       { 0x1a, 0x411111f0 },
+                       { 0x1b, 0x411111f0 },
+                       { 0x1d, 0x40f89b2d },
+                       { 0x1e, 0x411111f0 },
+                       { 0x21, 0x0321101f },
+                       { },
+               },
+       },
 
 };
 
@@ -4821,6 +4885,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1025, 0x0740, "Acer AO725", ALC271_FIXUP_HP_GATE_MIC_JACK),
        SND_PCI_QUIRK(0x1025, 0x0742, "Acer AO756", ALC271_FIXUP_HP_GATE_MIC_JACK),
        SND_PCI_QUIRK(0x1025, 0x0775, "Acer Aspire E1-572", ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572),
+       SND_PCI_QUIRK(0x1025, 0x079b, "Acer Aspire V5-573G", ALC282_FIXUP_ASPIRE_V5_PINS),
        SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
        SND_PCI_QUIRK(0x1028, 0x05bd, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x05be, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
@@ -5279,27 +5344,30 @@ static void alc269_fill_coef(struct hda_codec *codec)
        if ((alc_get_coef0(codec) & 0x00ff) == 0x017) {
                val = alc_read_coef_idx(codec, 0x04);
                /* Power up output pin */
-               alc_write_coef_idx(codec, 0x04, val | (1<<11));
+               if (val != -1)
+                       alc_write_coef_idx(codec, 0x04, val | (1<<11));
        }
 
        if ((alc_get_coef0(codec) & 0x00ff) == 0x018) {
                val = alc_read_coef_idx(codec, 0xd);
-               if ((val & 0x0c00) >> 10 != 0x1) {
+               if (val != -1 && (val & 0x0c00) >> 10 != 0x1) {
                        /* Capless ramp up clock control */
                        alc_write_coef_idx(codec, 0xd, val | (1<<10));
                }
                val = alc_read_coef_idx(codec, 0x17);
-               if ((val & 0x01c0) >> 6 != 0x4) {
+               if (val != -1 && (val & 0x01c0) >> 6 != 0x4) {
                        /* Class D power on reset */
                        alc_write_coef_idx(codec, 0x17, val | (1<<7));
                }
        }
 
        val = alc_read_coef_idx(codec, 0xd); /* Class D */
-       alc_write_coef_idx(codec, 0xd, val | (1<<14));
+       if (val != -1)
+               alc_write_coef_idx(codec, 0xd, val | (1<<14));
 
        val = alc_read_coef_idx(codec, 0x4); /* HP */
-       alc_write_coef_idx(codec, 0x4, val | (1<<11));
+       if (val != -1)
+               alc_write_coef_idx(codec, 0x4, val | (1<<11));
 }
 
 /*
@@ -5384,6 +5452,7 @@ static int patch_alc269(struct hda_codec *codec)
        case 0x10ec0286:
        case 0x10ec0288:
                spec->codec_variant = ALC269_TYPE_ALC286;
+               spec->shutup = alc286_shutup;
                break;
        case 0x10ec0255:
                spec->codec_variant = ALC269_TYPE_ALC255;
index bd41ee4da078c6c7808364db38d344eab4151a75..2c71f16bd6613fc3e07ca63c4a5b1d8f85efa874 100644 (file)
@@ -1278,6 +1278,8 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
        else
                rates = &arizona_48k_bclk_rates[0];
 
+       wl = snd_pcm_format_width(params_format(params));
+
        if (tdm_slots) {
                arizona_aif_dbg(dai, "Configuring for %d %d bit TDM slots\n",
                                tdm_slots, tdm_width);
@@ -1285,6 +1287,7 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
                channels = tdm_slots;
        } else {
                bclk_target = snd_soc_params_to_bclk(params);
+               tdm_width = wl;
        }
 
        if (chan_limit && chan_limit < channels) {
@@ -1319,8 +1322,7 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
        arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
                        rates[bclk], rates[bclk] / lrclk);
 
-       wl = snd_pcm_format_width(params_format(params));
-       frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl;
+       frame = wl << ARIZONA_AIF1TX_WL_SHIFT | tdm_width;
 
        reconfig = arizona_aif_cfg_changed(codec, base, bclk, lrclk, frame);
 
index a20b30ca52c09dc13507d55afef7854a23f29e40..98523209f7391852cb0e517fb373c6635e2ded99 100644 (file)
@@ -282,10 +282,10 @@ static const struct cs4265_clk_para clk_map_table[] = {
 
        /*64k*/
        {8192000, 64000, 1, 0},
-       {1228800, 64000, 1, 1},
-       {1693440, 64000, 1, 2},
-       {2457600, 64000, 1, 3},
-       {3276800, 64000, 1, 4},
+       {12288000, 64000, 1, 1},
+       {16934400, 64000, 1, 2},
+       {24576000, 64000, 1, 3},
+       {32768000, 64000, 1, 4},
 
        /* 88.2k */
        {11289600, 88200, 1, 0},
@@ -435,10 +435,10 @@ static int cs4265_pcm_hw_params(struct snd_pcm_substream *substream,
        index = cs4265_get_clk_index(cs4265->sysclk, params_rate(params));
        if (index >= 0) {
                snd_soc_update_bits(codec, CS4265_ADC_CTL,
-                       CS4265_ADC_FM, clk_map_table[index].fm_mode);
+                       CS4265_ADC_FM, clk_map_table[index].fm_mode << 6);
                snd_soc_update_bits(codec, CS4265_MCLK_FREQ,
                        CS4265_MCLK_FREQ_MASK,
-                       clk_map_table[index].mclkdiv);
+                       clk_map_table[index].mclkdiv << 4);
 
        } else {
                dev_err(codec->dev, "can't get correct mclk\n");
index 1dceafeec4151b4ae85b629aaa61e0737de73c34..f586cbd30b776ead146eb7f0edb4d11f7c74f013 100644 (file)
@@ -11,7 +11,7 @@
  */
 
 #ifndef __DA732X_H_
-#define __DA732X_H
+#define __DA732X_H_
 
 #include <sound/soc.h>
 
index 163ec3855fd4027e01a1067fa6842688f0175f4b..0c8aefab404ca15cabfaaf43a36d1885983476ed 100644 (file)
@@ -259,13 +259,13 @@ static const struct soc_enum pcm512x_veds =
                        pcm512x_ramp_step_text);
 
 static const struct snd_kcontrol_new pcm512x_controls[] = {
-SOC_DOUBLE_R_TLV("Playback Digital Volume", PCM512x_DIGITAL_VOLUME_2,
+SOC_DOUBLE_R_TLV("Digital Playback Volume", PCM512x_DIGITAL_VOLUME_2,
                 PCM512x_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv),
 SOC_DOUBLE_TLV("Playback Volume", PCM512x_ANALOG_GAIN_CTRL,
               PCM512x_LAGN_SHIFT, PCM512x_RAGN_SHIFT, 1, 1, analog_tlv),
 SOC_DOUBLE_TLV("Playback Boost Volume", PCM512x_ANALOG_GAIN_BOOST,
               PCM512x_AGBL_SHIFT, PCM512x_AGBR_SHIFT, 1, 0, boost_tlv),
-SOC_DOUBLE("Playback Digital Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT,
+SOC_DOUBLE("Digital Playback Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT,
           PCM512x_RQMR_SHIFT, 1, 1),
 
 SOC_SINGLE("Deemphasis Switch", PCM512x_DSP, PCM512x_DEMP_SHIFT, 1, 1),
index 6bc6efdec550db684e4f8bfa32bd88107902d9cd..f1ec6e6bd08aced4be7c38d868ccba94a655c5f7 100644 (file)
@@ -2059,6 +2059,7 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5640 = {
 static const struct regmap_config rt5640_regmap = {
        .reg_bits = 8,
        .val_bits = 16,
+       .use_single_rw = true,
 
        .max_register = RT5640_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5640_ranges) *
                                               RT5640_PR_SPACING),
index 67f14556462ff35bd6601062fc55a40ec2a96310..5337c448b5e365de204a95e3a945291dd228844b 100644 (file)
@@ -2135,10 +2135,10 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
        { "BST2", NULL, "IN2P" },
        { "BST2", NULL, "IN2N" },
 
-       { "IN1P", NULL, "micbias1" },
-       { "IN1N", NULL, "micbias1" },
-       { "IN2P", NULL, "micbias1" },
-       { "IN2N", NULL, "micbias1" },
+       { "IN1P", NULL, "MICBIAS1" },
+       { "IN1N", NULL, "MICBIAS1" },
+       { "IN2P", NULL, "MICBIAS1" },
+       { "IN2N", NULL, "MICBIAS1" },
 
        { "ADC 1", NULL, "BST1" },
        { "ADC 1", NULL, "ADC 1 power" },
index c28508da34cf3ba4354ba6d54de685a03d112ca4..6a6b2ff7d7d73daf4b6742242af4247e5585ebcc 100644 (file)
@@ -403,7 +403,8 @@ out:
        return ret;
 }
 
-static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div)
+static int __davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id,
+                                     int div, bool explicit)
 {
        struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
 
@@ -420,7 +421,8 @@ static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div
                               ACLKXDIV(div - 1), ACLKXDIV_MASK);
                mcasp_mod_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG,
                               ACLKRDIV(div - 1), ACLKRDIV_MASK);
-               mcasp->bclk_div = div;
+               if (explicit)
+                       mcasp->bclk_div = div;
                break;
 
        case 2:         /* BCLK/LRCLK ratio */
@@ -434,6 +436,12 @@ static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div
        return 0;
 }
 
+static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id,
+                                   int div)
+{
+       return __davinci_mcasp_set_clkdiv(dai, div_id, div, 1);
+}
+
 static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id,
                                    unsigned int freq, int dir)
 {
@@ -738,7 +746,7 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
                                 "Inaccurate BCLK: %u Hz / %u != %u Hz\n",
                                 mcasp->sysclk_freq, div, bclk_freq);
                }
-               davinci_mcasp_set_clkdiv(cpu_dai, 1, div);
+               __davinci_mcasp_set_clkdiv(cpu_dai, 1, div, 0);
        }
 
        ret = mcasp_common_hw_param(mcasp, substream->stream,
index f54a8fc992913ee837ee8c2914599274982bbba2..f3012b645b51fcfdcdbc5c2e60b8f1d5db11724f 100644 (file)
@@ -49,7 +49,6 @@ config SND_SOC_FSL_ESAI
        tristate "Enhanced Serial Audio Interface (ESAI) module support"
        select REGMAP_MMIO
        select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n
-       select SND_SOC_FSL_UTILS
        help
          Say Y if you want to add Enhanced Synchronous Audio Interface
          (ESAI) support for the Freescale CPUs.
index 72d154e7dd03c3695860dd4da8b00fd6bc2ff3c5..a3b29ed84963459baada6cc9d8ab742f696ee44e 100644 (file)
@@ -18,7 +18,6 @@
 
 #include "fsl_esai.h"
 #include "imx-pcm.h"
-#include "fsl_utils.h"
 
 #define FSL_ESAI_RATES         SNDRV_PCM_RATE_8000_192000
 #define FSL_ESAI_FORMATS       (SNDRV_PCM_FMTBIT_S8 | \
@@ -607,7 +606,6 @@ static struct snd_soc_dai_ops fsl_esai_dai_ops = {
        .hw_params = fsl_esai_hw_params,
        .set_sysclk = fsl_esai_set_dai_sysclk,
        .set_fmt = fsl_esai_set_dai_fmt,
-       .xlate_tdm_slot_mask = fsl_asoc_xlate_tdm_slot_mask,
        .set_tdm_slot = fsl_esai_set_dai_tdm_slot,
 };
 
index 159e517fa09aa6ee5d061e658cafcd9d0f8f12a5..cef7776b712cff43f37f81648a6fe2a59256ddd9 100644 (file)
@@ -481,12 +481,19 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
        snd_soc_card_set_drvdata(&priv->snd_card, priv);
 
        ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card);
+       if (ret >= 0)
+               return ret;
 
 err:
        asoc_simple_card_unref(pdev);
        return ret;
 }
 
+static int asoc_simple_card_remove(struct platform_device *pdev)
+{
+       return asoc_simple_card_unref(pdev);
+}
+
 static const struct of_device_id asoc_simple_of_match[] = {
        { .compatible = "simple-audio-card", },
        {},
@@ -500,6 +507,7 @@ static struct platform_driver asoc_simple_card = {
                .of_match_table = asoc_simple_of_match,
        },
        .probe = asoc_simple_card_probe,
+       .remove = asoc_simple_card_remove,
 };
 
 module_platform_driver(asoc_simple_card);
index 42edc6f4fc4a839d49140710adcf191f19b7e4a4..03d0a166b6359243a12e046aa64264dc647f4cdd 100644 (file)
@@ -246,8 +246,8 @@ static struct sst_acpi_desc sst_acpi_broadwell_desc = {
 };
 
 static struct sst_acpi_mach baytrail_machines[] = {
-       { "10EC5640", "byt-rt5640", "intel/fw_sst_0f28.bin-i2s_master" },
-       { "193C9890", "byt-max98090", "intel/fw_sst_0f28.bin-i2s_master" },
+       { "10EC5640", "byt-rt5640", "intel/fw_sst_0f28.bin-48kHz_i2s_master" },
+       { "193C9890", "byt-max98090", "intel/fw_sst_0f28.bin-48kHz_i2s_master" },
        {}
 };
 
index 67673a2c0f415d9f120bf375a3f2a9ca722d7c9a..b4ad98c43e5c6d53a1654e75bc4577d82f15b305 100644 (file)
@@ -817,7 +817,7 @@ static struct sst_dsp_device byt_dev = {
        .ops = &sst_byt_ops,
 };
 
-int sst_byt_dsp_suspend_noirq(struct device *dev, struct sst_pdata *pdata)
+int sst_byt_dsp_suspend_late(struct device *dev, struct sst_pdata *pdata)
 {
        struct sst_byt *byt = pdata->dsp;
 
@@ -826,14 +826,6 @@ int sst_byt_dsp_suspend_noirq(struct device *dev, struct sst_pdata *pdata)
        sst_byt_drop_all(byt);
        dev_dbg(byt->dev, "dsp in reset\n");
 
-       return 0;
-}
-EXPORT_SYMBOL_GPL(sst_byt_dsp_suspend_noirq);
-
-int sst_byt_dsp_suspend_late(struct device *dev, struct sst_pdata *pdata)
-{
-       struct sst_byt *byt = pdata->dsp;
-
        dev_dbg(byt->dev, "free all blocks and unload fw\n");
        sst_fw_unload(byt->fw);
 
index 06a4d202689b3780e13d37a55594862735c0d129..8faff6dcf25d0c1328c799cf40b78620aa3c59d9 100644 (file)
@@ -66,7 +66,6 @@ int sst_byt_get_dsp_position(struct sst_byt *byt,
 int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata);
 void sst_byt_dsp_free(struct device *dev, struct sst_pdata *pdata);
 struct sst_dsp *sst_byt_get_dsp(struct sst_byt *byt);
-int sst_byt_dsp_suspend_noirq(struct device *dev, struct sst_pdata *pdata);
 int sst_byt_dsp_suspend_late(struct device *dev, struct sst_pdata *pdata);
 int sst_byt_dsp_boot(struct device *dev, struct sst_pdata *pdata);
 int sst_byt_dsp_wait_for_ready(struct device *dev, struct sst_pdata *pdata);
index 599401c0c6551d59b1166359e0df5a45e74c8f8d..eab1c7d8518782b01e517e562c6dd7f9eb686d5c 100644 (file)
@@ -59,6 +59,9 @@ struct sst_byt_priv_data {
 
        /* DAI data */
        struct sst_byt_pcm_data pcm[BYT_PCM_COUNT];
+
+       /* flag indicating is stream context restore needed after suspend */
+       bool restore_stream;
 };
 
 /* this may get called several times by oss emulation */
@@ -184,7 +187,10 @@ static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
                sst_byt_stream_start(byt, pcm_data->stream, 0);
                break;
        case SNDRV_PCM_TRIGGER_RESUME:
-               schedule_work(&pcm_data->work);
+               if (pdata->restore_stream == true)
+                       schedule_work(&pcm_data->work);
+               else
+                       sst_byt_stream_resume(byt, pcm_data->stream);
                break;
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
                sst_byt_stream_resume(byt, pcm_data->stream);
@@ -193,6 +199,7 @@ static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
                sst_byt_stream_stop(byt, pcm_data->stream);
                break;
        case SNDRV_PCM_TRIGGER_SUSPEND:
+               pdata->restore_stream = false;
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
                sst_byt_stream_pause(byt, pcm_data->stream);
                break;
@@ -404,26 +411,10 @@ static const struct snd_soc_component_driver byt_dai_component = {
 };
 
 #ifdef CONFIG_PM
-static int sst_byt_pcm_dev_suspend_noirq(struct device *dev)
-{
-       struct sst_pdata *sst_pdata = dev_get_platdata(dev);
-       int ret;
-
-       dev_dbg(dev, "suspending noirq\n");
-
-       /* at this point all streams will be stopped and context saved */
-       ret = sst_byt_dsp_suspend_noirq(dev, sst_pdata);
-       if (ret < 0) {
-               dev_err(dev, "failed to suspend %d\n", ret);
-               return ret;
-       }
-
-       return ret;
-}
-
 static int sst_byt_pcm_dev_suspend_late(struct device *dev)
 {
        struct sst_pdata *sst_pdata = dev_get_platdata(dev);
+       struct sst_byt_priv_data *priv_data = dev_get_drvdata(dev);
        int ret;
 
        dev_dbg(dev, "suspending late\n");
@@ -434,34 +425,30 @@ static int sst_byt_pcm_dev_suspend_late(struct device *dev)
                return ret;
        }
 
+       priv_data->restore_stream = true;
+
        return ret;
 }
 
 static int sst_byt_pcm_dev_resume_early(struct device *dev)
 {
        struct sst_pdata *sst_pdata = dev_get_platdata(dev);
+       int ret;
 
        dev_dbg(dev, "resume early\n");
 
        /* load fw and boot DSP */
-       return sst_byt_dsp_boot(dev, sst_pdata);
-}
-
-static int sst_byt_pcm_dev_resume(struct device *dev)
-{
-       struct sst_pdata *sst_pdata = dev_get_platdata(dev);
-
-       dev_dbg(dev, "resume\n");
+       ret = sst_byt_dsp_boot(dev, sst_pdata);
+       if (ret)
+               return ret;
 
        /* wait for FW to finish booting */
        return sst_byt_dsp_wait_for_ready(dev, sst_pdata);
 }
 
 static const struct dev_pm_ops sst_byt_pm_ops = {
-       .suspend_noirq = sst_byt_pcm_dev_suspend_noirq,
        .suspend_late = sst_byt_pcm_dev_suspend_late,
        .resume_early = sst_byt_pcm_dev_resume_early,
-       .resume = sst_byt_pcm_dev_resume,
 };
 
 #define SST_BYT_PM_OPS (&sst_byt_pm_ops)
index f8a6adc2d81ca8cecec98a3b768cbc1ccef9b0c0..4336d1831485f77787f384d77ad4785fce6ad02a 100644 (file)
@@ -260,7 +260,7 @@ static struct snd_soc_dai_link omap_twl4030_dai_links[] = {
                .stream_name = "TWL4030 Voice",
                .cpu_dai_name = "omap-mcbsp.3",
                .codec_dai_name = "twl4030-voice",
-               .platform_name = "omap-mcbsp.2",
+               .platform_name = "omap-mcbsp.3",
                .codec_name = "twl4030-codec",
                .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF |
                           SND_SOC_DAIFMT_CBM_CFM,
index 0109f6c2334e528e757b0f128fbf2dddbd3f29de..a8e0974330749f86c894ce520ff43d7c4d0960cc 100644 (file)
@@ -765,9 +765,7 @@ static int pxa_ssp_remove(struct snd_soc_dai *dai)
                          SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | \
                          SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
 
-#define PXA_SSP_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
-                           SNDRV_PCM_FMTBIT_S24_LE |   \
-                           SNDRV_PCM_FMTBIT_S32_LE)
+#define PXA_SSP_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
 
 static const struct snd_soc_dai_ops pxa_ssp_dai_ops = {
        .startup        = pxa_ssp_startup,
index 3fdf3be7b99ab558e41fd26080b3bb80c5d53b59..f95e7ab135e83266f958c49801284a6e780744a3 100644 (file)
@@ -247,7 +247,7 @@ rsnd_gen2_dma_addr(struct rsnd_priv *priv,
        };
 
        /* it shouldn't happen */
-       if (use_dvc & !use_src)
+       if (use_dvc && !use_src)
                dev_err(dev, "DVC is selected without SRC\n");
 
        /* use SSIU or SSI ? */
index d4bfd4a9076fe02fd50495e0fee6f97471500bb5..889f4e3d35dc53548f59f159666fbc668f7bd39b 100644 (file)
@@ -1325,7 +1325,7 @@ static int soc_post_component_init(struct snd_soc_pcm_runtime *rtd,
        device_initialize(rtd->dev);
        rtd->dev->parent = rtd->card->dev;
        rtd->dev->release = rtd_release;
-       rtd->dev->init_name = name;
+       dev_set_name(rtd->dev, "%s", name);
        dev_set_drvdata(rtd->dev, rtd);
        mutex_init(&rtd->pcm_mutex);
        INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients);
index 8348352dc2c62c484a1efba6f04c290367b93864..177bd8639ef93e6b97a20e1cd022224e62cf14bf 100644 (file)
@@ -2860,12 +2860,14 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        unsigned int reg_val, val;
-       int ret = 0;
 
-       if (e->reg != SND_SOC_NOPM)
-               ret = soc_dapm_read(dapm, e->reg, &reg_val);
-       else
+       if (e->reg != SND_SOC_NOPM) {
+               int ret = soc_dapm_read(dapm, e->reg, &reg_val);
+               if (ret)
+                       return ret;
+       } else {
                reg_val = dapm_kcontrol_get_value(kcontrol);
+       }
 
        val = (reg_val >> e->shift_l) & e->mask;
        ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val);
@@ -2875,7 +2877,7 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
                ucontrol->value.enumerated.item[1] = val;
        }
 
-       return ret;
+       return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);
 
index 9577121ce971247407b6d04957de548a5b3fd67d..ca8037634100b0a814927f52da9d77fca28fd657 100644 (file)
@@ -21,7 +21,7 @@
  */
 
 #ifndef __TEGRA_ASOC_UTILS_H__
-#define __TEGRA_ASOC_UTILS_H_
+#define __TEGRA_ASOC_UTILS_H__
 
 struct clk;
 struct device;
index f652b10ce90582c2a2b72d8d11c74309ae2f0d3e..223c47b33ba30e767c7af227c974a57471d02b90 100644 (file)
@@ -1580,6 +1580,35 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                }
        }
 },
+{
+       /* BOSS ME-25 */
+       USB_DEVICE(0x0582, 0x0113),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = (const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 0,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 2,
+                               .type = QUIRK_MIDI_FIXED_ENDPOINT,
+                               .data = & (const struct snd_usb_midi_endpoint_info) {
+                                       .out_cables = 0x0001,
+                                       .in_cables  = 0x0001
+                               }
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
 {
        /* only 44.1 kHz works at the moment */
        USB_DEVICE(0x0582, 0x0120),
index d0396af99fa06570c71c110b6ba9b81e6a40dd76..5b1b807265a15e826e174a197c06b6c0788ff9b7 100644 (file)
@@ -267,90 +267,90 @@ int get_msr(int cpu, off_t offset, unsigned long long *msr)
 /*
  * Example Format w/ field column widths:
  *
- * Package    Core     CPU Avg_MHz Bzy_MHz TSC_MHz     SMI   %Busy CPU_%c1 CPU_%c3 CPU_%c6 CPU_%c7 CoreTmp  PkgTmp Pkg%pc2 Pkg%pc3 Pkg%pc6 Pkg%pc7 PkgWatt CorWatt GFXWatt
- * 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567
+ *  Package    Core     CPU Avg_MHz Bzy_MHz TSC_MHz     SMI   %Busy CPU_%c1 CPU_%c3 CPU_%c6 CPU_%c7 CoreTmp  PkgTmp Pkg%pc2 Pkg%pc3 Pkg%pc6 Pkg%pc7 PkgWatt CorWatt GFXWatt
+ * 123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678
  */
 
 void print_header(void)
 {
        if (show_pkg)
-               outp += sprintf(outp, "Package ");
+               outp += sprintf(outp, " Package");
        if (show_core)
-               outp += sprintf(outp, "    Core ");
+               outp += sprintf(outp, "    Core");
        if (show_cpu)
-               outp += sprintf(outp, "    CPU ");
+               outp += sprintf(outp, "     CPU");
        if (has_aperf)
-               outp += sprintf(outp, "Avg_MHz ");
+               outp += sprintf(outp, " Avg_MHz");
        if (do_nhm_cstates)
-               outp += sprintf(outp, "  %%Busy ");
+               outp += sprintf(outp, "   %%Busy");
        if (has_aperf)
-               outp += sprintf(outp, "Bzy_MHz ");
-       outp += sprintf(outp, "TSC_MHz ");
+               outp += sprintf(outp, " Bzy_MHz");
+       outp += sprintf(outp, " TSC_MHz");
        if (do_smi)
-               outp += sprintf(outp, "    SMI ");
+               outp += sprintf(outp, "     SMI");
        if (extra_delta_offset32)
-               outp += sprintf(outp, " count 0x%03X ", extra_delta_offset32);
+               outp += sprintf(outp, "  count 0x%03X", extra_delta_offset32);
        if (extra_delta_offset64)
-               outp += sprintf(outp, " COUNT 0x%03X ", extra_delta_offset64);
+               outp += sprintf(outp, "  COUNT 0x%03X", extra_delta_offset64);
        if (extra_msr_offset32)
-               outp += sprintf(outp, "  MSR 0x%03X ", extra_msr_offset32);
+               outp += sprintf(outp, "   MSR 0x%03X", extra_msr_offset32);
        if (extra_msr_offset64)
-               outp += sprintf(outp, "          MSR 0x%03X ", extra_msr_offset64);
+               outp += sprintf(outp, "           MSR 0x%03X", extra_msr_offset64);
        if (do_nhm_cstates)
-               outp += sprintf(outp, " CPU%%c1 ");
+               outp += sprintf(outp, "  CPU%%c1");
        if (do_nhm_cstates && !do_slm_cstates)
-               outp += sprintf(outp, " CPU%%c3 ");
+               outp += sprintf(outp, "  CPU%%c3");
        if (do_nhm_cstates)
-               outp += sprintf(outp, " CPU%%c6 ");
+               outp += sprintf(outp, "  CPU%%c6");
        if (do_snb_cstates)
-               outp += sprintf(outp, " CPU%%c7 ");
+               outp += sprintf(outp, "  CPU%%c7");
 
        if (do_dts)
-               outp += sprintf(outp, "CoreTmp ");
+               outp += sprintf(outp, " CoreTmp");
        if (do_ptm)
-               outp += sprintf(outp, " PkgTmp ");
+               outp += sprintf(outp, "  PkgTmp");
 
        if (do_snb_cstates)
-               outp += sprintf(outp, "Pkg%%pc2 ");
+               outp += sprintf(outp, " Pkg%%pc2");
        if (do_nhm_cstates && !do_slm_cstates)
-               outp += sprintf(outp, "Pkg%%pc3 ");
+               outp += sprintf(outp, " Pkg%%pc3");
        if (do_nhm_cstates && !do_slm_cstates)
-               outp += sprintf(outp, "Pkg%%pc6 ");
+               outp += sprintf(outp, " Pkg%%pc6");
        if (do_snb_cstates)
-               outp += sprintf(outp, "Pkg%%pc7 ");
+               outp += sprintf(outp, " Pkg%%pc7");
        if (do_c8_c9_c10) {
-               outp += sprintf(outp, "Pkg%%pc8 ");
-               outp += sprintf(outp, "Pkg%%pc9 ");
-               outp += sprintf(outp, "Pk%%pc10 ");
+               outp += sprintf(outp, " Pkg%%pc8");
+               outp += sprintf(outp, " Pkg%%pc9");
+               outp += sprintf(outp, " Pk%%pc10");
        }
 
        if (do_rapl && !rapl_joules) {
                if (do_rapl & RAPL_PKG)
-                       outp += sprintf(outp, "PkgWatt ");
+                       outp += sprintf(outp, " PkgWatt");
                if (do_rapl & RAPL_CORES)
-                       outp += sprintf(outp, "CorWatt ");
+                       outp += sprintf(outp, " CorWatt");
                if (do_rapl & RAPL_GFX)
-                       outp += sprintf(outp, "GFXWatt ");
+                       outp += sprintf(outp, " GFXWatt");
                if (do_rapl & RAPL_DRAM)
-                       outp += sprintf(outp, "RAMWatt ");
+                       outp += sprintf(outp, " RAMWatt");
                if (do_rapl & RAPL_PKG_PERF_STATUS)
-                       outp += sprintf(outp, "  PKG_%% ");
+                       outp += sprintf(outp, "   PKG_%%");
                if (do_rapl & RAPL_DRAM_PERF_STATUS)
-                       outp += sprintf(outp, "  RAM_%% ");
+                       outp += sprintf(outp, "   RAM_%%");
        } else {
                if (do_rapl & RAPL_PKG)
-                       outp += sprintf(outp, "  Pkg_J ");
+                       outp += sprintf(outp, "   Pkg_J");
                if (do_rapl & RAPL_CORES)
-                       outp += sprintf(outp, "  Cor_J ");
+                       outp += sprintf(outp, "   Cor_J");
                if (do_rapl & RAPL_GFX)
-                       outp += sprintf(outp, "  GFX_J ");
+                       outp += sprintf(outp, "   GFX_J");
                if (do_rapl & RAPL_DRAM)
-                       outp += sprintf(outp, "  RAM_W ");
+                       outp += sprintf(outp, "   RAM_W");
                if (do_rapl & RAPL_PKG_PERF_STATUS)
-                       outp += sprintf(outp, "  PKG_%% ");
+                       outp += sprintf(outp, "   PKG_%%");
                if (do_rapl & RAPL_DRAM_PERF_STATUS)
-                       outp += sprintf(outp, "  RAM_%% ");
-               outp += sprintf(outp, "  time ");
+                       outp += sprintf(outp, "   RAM_%%");
+               outp += sprintf(outp, "   time");
 
        }
        outp += sprintf(outp, "\n");
index 5386fd7c43ae984094c3a09ad48478fbc58d343f..74bbefdeaf4c187b07c02e67fedd74619f6215d6 100644 (file)
@@ -1,18 +1,18 @@
 uname_M := $(shell uname -m 2>/dev/null || echo not)
 ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/)
 ifeq ($(ARCH),i386)
-        ARCH := X86
+        ARCH := x86
        CFLAGS := -DCONFIG_X86_32 -D__i386__
 endif
 ifeq ($(ARCH),x86_64)
-       ARCH := X86
+       ARCH := x86
        CFLAGS := -DCONFIG_X86_64 -D__x86_64__
 endif
 
 CFLAGS += -I../../../../usr/include/
 
 all:
-ifeq ($(ARCH),X86)
+ifeq ($(ARCH),x86)
        gcc $(CFLAGS) msgque.c -o msgque_test
 else
        echo "Not an x86 target, can't build msgque selftest"
index d7d6bbeeff2f22a175939d218bce02398ce206c8..8aabd82db9e4a3028c6f8b594304e8896f427c77 100644 (file)
@@ -1,11 +1,11 @@
 uname_M := $(shell uname -m 2>/dev/null || echo not)
 ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/)
 ifeq ($(ARCH),i386)
-        ARCH := X86
+        ARCH := x86
        CFLAGS := -DCONFIG_X86_32 -D__i386__
 endif
 ifeq ($(ARCH),x86_64)
-       ARCH := X86
+       ARCH := x86
        CFLAGS := -DCONFIG_X86_64 -D__x86_64__
 endif
 
@@ -15,7 +15,7 @@ CFLAGS += -I../../../../usr/include/
 CFLAGS += -I../../../../arch/x86/include/
 
 all:
-ifeq ($(ARCH),X86)
+ifeq ($(ARCH),x86)
        gcc $(CFLAGS) kcmp_test.c -o kcmp_test
 else
        echo "Not an x86 target, can't build kcmp selftest"
index 6816c491c5ffcbdecec409fd10592455fb603b62..ad4ab01cd28ffabed4f290e34b195e4895f7a400 100644 (file)
@@ -1,10 +1,10 @@
 uname_M := $(shell uname -m 2>/dev/null || echo not)
 ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/)
 ifeq ($(ARCH),i386)
-       ARCH := X86
+       ARCH := x86
 endif
 ifeq ($(ARCH),x86_64)
-       ARCH := X86
+       ARCH := x86
 endif
 
 CFLAGS += -D_FILE_OFFSET_BITS=64
@@ -14,20 +14,20 @@ CFLAGS += -I../../../../include/uapi/
 CFLAGS += -I../../../../include/
 
 all:
-ifeq ($(ARCH),X86)
+ifeq ($(ARCH),x86)
        gcc $(CFLAGS) memfd_test.c -o memfd_test
 else
        echo "Not an x86 target, can't build memfd selftest"
 endif
 
 run_tests: all
-ifeq ($(ARCH),X86)
+ifeq ($(ARCH),x86)
        gcc $(CFLAGS) memfd_test.c -o memfd_test
 endif
        @./memfd_test || echo "memfd_test: [FAIL]"
 
 build_fuse:
-ifeq ($(ARCH),X86)
+ifeq ($(ARCH),x86)
        gcc $(CFLAGS) fuse_mnt.c `pkg-config fuse --cflags --libs` -o fuse_mnt
        gcc $(CFLAGS) fuse_test.c -o fuse_test
 else
diff --git a/tools/usb/usbip/.gitignore b/tools/usb/usbip/.gitignore
new file mode 100644 (file)
index 0000000..9aad9e3
--- /dev/null
@@ -0,0 +1,28 @@
+Makefile
+Makefile.in
+aclocal.m4
+autom4te.cache/
+config.guess
+config.h
+config.h.in
+config.log
+config.status
+config.sub
+configure
+depcomp
+install-sh
+libsrc/Makefile
+libsrc/Makefile.in
+libtool
+ltmain.sh
+missing
+src/Makefile
+src/Makefile.in
+stamp-h1
+libsrc/libusbip.la
+libsrc/libusbip_la-names.lo
+libsrc/libusbip_la-usbip_common.lo
+libsrc/libusbip_la-usbip_host_driver.lo
+libsrc/libusbip_la-vhci_driver.lo
+src/usbip
+src/usbipd
diff --git a/tools/usb/usbip/AUTHORS b/tools/usb/usbip/AUTHORS
new file mode 100644 (file)
index 0000000..a27ea8d
--- /dev/null
@@ -0,0 +1,3 @@
+Takahiro Hirofuchi
+Robert Leibl
+matt mooney <mfm@muteddisk.com>
diff --git a/tools/usb/usbip/COPYING b/tools/usb/usbip/COPYING
new file mode 100644 (file)
index 0000000..c5611e4
--- /dev/null
@@ -0,0 +1,340 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/tools/usb/usbip/INSTALL b/tools/usb/usbip/INSTALL
new file mode 100644 (file)
index 0000000..d3c5b40
--- /dev/null
@@ -0,0 +1,237 @@
+Installation Instructions
+*************************
+
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
+2006, 2007 Free Software Foundation, Inc.
+
+This file is free documentation; the Free Software Foundation gives
+unlimited permission to copy, distribute and modify it.
+
+Basic Installation
+==================
+
+Briefly, the shell commands `./configure; make; make install' should
+configure, build, and install this package.  The following
+more-detailed instructions are generic; see the `README' file for
+instructions specific to this package.
+
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions.  Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+   It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring.  Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.
+
+   If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release.  If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+   The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'.  You need `configure.ac' if
+you want to change it or regenerate `configure' using a newer version
+of `autoconf'.
+
+The simplest way to compile this package is:
+
+  1. `cd' to the directory containing the package's source code and type
+     `./configure' to configure the package for your system.
+
+     Running `configure' might take a while.  While running, it prints
+     some messages telling which features it is checking for.
+
+  2. Type `make' to compile the package.
+
+  3. Optionally, type `make check' to run any self-tests that come with
+     the package.
+
+  4. Type `make install' to install the programs and any data files and
+     documentation.
+
+  5. You can remove the program binaries and object files from the
+     source code directory by typing `make clean'.  To also remove the
+     files that `configure' created (so you can compile the package for
+     a different kind of computer), type `make distclean'.  There is
+     also a `make maintainer-clean' target, but that is intended mainly
+     for the package's developers.  If you use it, you may have to get
+     all sorts of other programs in order to regenerate files that came
+     with the distribution.
+
+  6. Often, you can also type `make uninstall' to remove the installed
+     files again.
+
+Compilers and Options
+=====================
+
+Some systems require unusual options for compilation or linking that the
+`configure' script does not know about.  Run `./configure --help' for
+details on some of the pertinent environment variables.
+
+   You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment.  Here
+is an example:
+
+     ./configure CC=c99 CFLAGS=-g LIBS=-lposix
+
+   *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory.  To do this, you can use GNU `make'.  `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script.  `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+   With a non-GNU `make', it is safer to compile the package for one
+architecture at a time in the source code directory.  After you have
+installed the package for one architecture, use `make distclean' before
+reconfiguring for another architecture.
+
+Installation Names
+==================
+
+By default, `make install' installs the package's commands under
+`/usr/local/bin', include files under `/usr/local/include', etc.  You
+can specify an installation prefix other than `/usr/local' by giving
+`configure' the option `--prefix=PREFIX'.
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+pass the option `--exec-prefix=PREFIX' to `configure', the package uses
+PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files still use the regular prefix.
+
+   In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' to specify different values for particular
+kinds of files.  Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System).  The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+There may be some features `configure' cannot figure out automatically,
+but needs to determine by the type of machine the package will run on.
+Usually, assuming the package is built to be run on the _same_
+architectures, `configure' can figure that out, but if it prints a
+message saying it cannot guess the machine type, give it the
+`--build=TYPE' option.  TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+     CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+     OS KERNEL-OS
+
+   See the file `config.sub' for the possible values of each field.  If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+   If you are _building_ compiler tools for cross-compiling, you should
+use the option `--target=TYPE' to select the type of system they will
+produce code for.
+
+   If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+If you want to set default values for `configure' scripts to share, you
+can create a site shell script called `config.site' that gives default
+values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists.  Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+Variables not defined in a site shell script can be set in the
+environment passed to `configure'.  However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost.  In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'.  For example:
+
+     ./configure CC=/usr/local2/bin/gcc
+
+causes the specified `gcc' to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+Unfortunately, this technique does not work for `CONFIG_SHELL' due to
+an Autoconf bug.  Until the bug is fixed you can use this workaround:
+
+     CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+`configure' Invocation
+======================
+
+`configure' recognizes the following options to control how it operates.
+
+`--help'
+`-h'
+     Print a summary of the options to `configure', and exit.
+
+`--version'
+`-V'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`--cache-file=FILE'
+     Enable the cache: use and save the results of the tests in FILE,
+     traditionally `config.cache'.  FILE defaults to `/dev/null' to
+     disable caching.
+
+`--config-cache'
+`-C'
+     Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+     Do not print messages saying which checks are being made.  To
+     suppress all normal output, redirect it to `/dev/null' (any error
+     messages will still be shown).
+
+`--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     `configure' can determine that directory automatically.
+
+`configure' also accepts some other, not widely useful, options.  Run
+`configure --help' for more details.
+
diff --git a/tools/usb/usbip/Makefile.am b/tools/usb/usbip/Makefile.am
new file mode 100644 (file)
index 0000000..66f8bf0
--- /dev/null
@@ -0,0 +1,6 @@
+SUBDIRS := libsrc src
+includedir = @includedir@/usbip
+include_HEADERS := $(addprefix libsrc/, \
+                    usbip_common.h vhci_driver.h usbip_host_driver.h)
+
+dist_man_MANS := $(addprefix doc/, usbip.8 usbipd.8)
diff --git a/tools/usb/usbip/README b/tools/usb/usbip/README
new file mode 100644 (file)
index 0000000..831f49f
--- /dev/null
@@ -0,0 +1,202 @@
+#
+# README for usbip-utils
+#
+# Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
+#               2005-2008 Takahiro Hirofuchi
+
+
+[Requirements]
+    - USB/IP device drivers
+       Found in the staging directory of the Linux kernel.
+
+    - libudev >= 2.0
+       libudev library
+
+    - libwrap0-dev
+       tcp wrapper library
+
+    - gcc >= 4.0
+
+    - libtool, automake >= 1.9, autoconf >= 2.5.0, pkg-config
+
+[Optional]
+    - hwdata
+        Contains USB device identification data.
+
+
+[Install]
+    0. Generate configuration scripts.
+       $ ./autogen.sh
+
+    1. Compile & install the userspace utilities.
+       $ ./configure [--with-tcp-wrappers=no] [--with-usbids-dir=<dir>]
+       $ make install
+
+    2. Compile & install USB/IP drivers.
+
+
+[Usage]
+    server:# (Physically attach your USB device.)
+
+    server:# insmod usbip-core.ko
+    server:# insmod usbip-host.ko
+
+    server:# usbipd -D
+       - Start usbip daemon.
+
+    server:# usbip list -l
+       - List driver assignments for USB devices.
+
+    server:# usbip bind --busid 1-2
+       - Bind usbip-host.ko to the device with busid 1-2.
+       - The USB device 1-2 is now exportable to other hosts!
+       - Use `usbip unbind --busid 1-2' to stop exporting the device.
+
+    client:# insmod usbip-core.ko
+    client:# insmod vhci-hcd.ko
+
+    client:# usbip list --remote <host>
+       - List exported USB devices on the <host>.
+
+    client:# usbip attach --remote <host> --busid 1-2
+       - Connect the remote USB device.
+
+    client:# usbip port
+       - Show virtual port status.
+
+    client:# usbip detach --port <port>
+       - Detach the USB device.
+
+
+[Example]
+---------------------------
+       SERVER SIDE
+---------------------------
+Physically attach your USB devices to this host.
+
+    trois:# insmod path/to/usbip-core.ko
+    trois:# insmod path/to/usbip-host.ko
+    trois:# usbipd -D
+
+In another terminal, let's look up what USB devices are physically
+attached to this host.
+
+    trois:# usbip list -l
+    Local USB devices
+    =================
+     - busid 1-1 (05a9:a511)
+            1-1:1.0 -> ov511
+
+     - busid 3-2 (0711:0902)
+            3-2:1.0 -> none
+
+     - busid 3-3.1 (08bb:2702)
+            3-3.1:1.0 -> snd-usb-audio
+            3-3.1:1.1 -> snd-usb-audio
+
+     - busid 3-3.2 (04bb:0206)
+            3-3.2:1.0 -> usb-storage
+
+     - busid 3-3 (0409:0058)
+            3-3:1.0 -> hub
+
+     - busid 4-1 (046d:08b2)
+            4-1:1.0 -> none
+            4-1:1.1 -> none
+            4-1:1.2 -> none
+
+     - busid 5-2 (058f:9254)
+            5-2:1.0 -> hub
+
+A USB storage device of busid 3-3.2 is now bound to the usb-storage
+driver. To export this device, we first mark the device as
+"exportable"; the device is bound to the usbip-host driver. Please
+remember you can not export a USB hub.
+
+Mark the device of busid 3-3.2 as exportable:
+
+    trois:# usbip --debug bind --busid 3-3.2
+    ...
+    usbip debug: usbip_bind.c:162:[unbind_other] 3-3.2:1.0 -> usb-storage
+    ...
+    bind device on busid 3-3.2: complete
+
+    trois:# usbip list -l
+    Local USB devices
+    =================
+    ...
+
+     - busid 3-3.2 (04bb:0206)
+            3-3.2:1.0 -> usbip-host
+    ...
+
+---------------------------
+       CLIENT SIDE
+---------------------------
+First, let's list available remote devices that are marked as
+exportable on the host.
+
+    deux:# insmod path/to/usbip-core.ko
+    deux:# insmod path/to/vhci-hcd.ko
+
+    deux:# usbip list --remote 10.0.0.3
+    Exportable USB devices
+    ======================
+     - 10.0.0.3
+           1-1: Prolific Technology, Inc. : unknown product (067b:3507)
+              : /sys/devices/pci0000:00/0000:00:1f.2/usb1/1-1
+              : (Defined at Interface level) / unknown subclass / unknown protocol (00/00/00)
+              :  0 - Mass Storage / SCSI / Bulk (Zip) (08/06/50)
+
+       1-2.2.1: Apple Computer, Inc. : unknown product (05ac:0203)
+              : /sys/devices/pci0000:00/0000:00:1f.2/usb1/1-2/1-2.2/1-2.2.1
+              : (Defined at Interface level) / unknown subclass / unknown protocol (00/00/00)
+              :  0 - Human Interface Devices / Boot Interface Subclass / Keyboard (03/01/01)
+
+       1-2.2.3: OmniVision Technologies, Inc. : OV511+ WebCam (05a9:a511)
+              : /sys/devices/pci0000:00/0000:00:1f.2/usb1/1-2/1-2.2/1-2.2.3
+              : (Defined at Interface level) / unknown subclass / unknown protocol (00/00/00)
+              :  0 - Vendor Specific Class / unknown subclass / unknown protocol (ff/00/00)
+
+           3-1: Logitech, Inc. : QuickCam Pro 4000 (046d:08b2)
+              : /sys/devices/pci0000:00/0000:00:1e.0/0000:02:0a.0/usb3/3-1
+              : (Defined at Interface level) / unknown subclass / unknown protocol (00/00/00)
+              :  0 - Data / unknown subclass / unknown protocol (0a/ff/00)
+              :  1 - Audio / Control Device / unknown protocol (01/01/00)
+              :  2 - Audio / Streaming / unknown protocol (01/02/00)
+
+Attach a remote USB device:
+
+    deux:# usbip attach --remote 10.0.0.3 --busid 1-1
+    port 0 attached
+
+Show the devices attached to this client:
+
+    deux:# usbip port
+    Port 00: <Port in Use> at Full Speed(12Mbps)
+          Prolific Technology, Inc. : unknown product (067b:3507)
+          6-1 -> usbip://10.0.0.3:3240/1-1  (remote bus/dev 001/004)
+          6-1:1.0 used by usb-storage
+                         /sys/class/scsi_device/0:0:0:0/device
+                         /sys/class/scsi_host/host0/device
+                         /sys/block/sda/device
+
+Detach the imported device:
+
+    deux:# usbip detach --port 0
+    port 0 detached
+
+
+[Checklist]
+    - See 'Debug Tips' on the project wiki.
+       - http://usbip.wiki.sourceforge.net/how-to-debug-usbip
+    - usbip-host.ko must be bound to the target device.
+       - See /proc/bus/usb/devices and find "Driver=..." lines of the device.
+    - Shutdown firewall.
+       - usbip now uses TCP port 3240.
+    - Disable SELinux.
+    - Check the kernel and daemon messages.
+
+
+[Contact]
+    Mailing List: linux-usb@vger.kernel.org
diff --git a/tools/usb/usbip/autogen.sh b/tools/usb/usbip/autogen.sh
new file mode 100755 (executable)
index 0000000..e1112d3
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/sh -x
+
+#aclocal
+#autoheader
+#libtoolize --copy --force
+#automake-1.9 -acf
+#autoconf
+
+autoreconf -i -f -v
diff --git a/tools/usb/usbip/cleanup.sh b/tools/usb/usbip/cleanup.sh
new file mode 100755 (executable)
index 0000000..955c3cc
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+if [ -r Makefile ]; then
+       make distclean
+fi
+
+FILES="aclocal.m4 autom4te.cache compile config.guess config.h.in config.log \
+       config.status config.sub configure cscope.out depcomp install-sh      \
+       libsrc/Makefile libsrc/Makefile.in libtool ltmain.sh Makefile         \
+       Makefile.in missing src/Makefile src/Makefile.in"
+
+rm -vRf $FILES
diff --git a/tools/usb/usbip/configure.ac b/tools/usb/usbip/configure.ac
new file mode 100644 (file)
index 0000000..607d05c
--- /dev/null
@@ -0,0 +1,111 @@
+dnl Process this file with autoconf to produce a configure script.
+
+AC_PREREQ(2.59)
+AC_INIT([usbip-utils], [2.0], [linux-usb@vger.kernel.org])
+AC_DEFINE([USBIP_VERSION], [0x00000111], [binary-coded decimal version number])
+
+CURRENT=0
+REVISION=1
+AGE=0
+AC_SUBST([LIBUSBIP_VERSION], [$CURRENT:$REVISION:$AGE], [library version])
+
+AC_CONFIG_SRCDIR([src/usbipd.c])
+AC_CONFIG_HEADERS([config.h])
+
+AM_INIT_AUTOMAKE([foreign])
+LT_INIT
+
+# Silent build for automake >= 1.11
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+
+AC_SUBST([EXTRA_CFLAGS], ["-Wall -Werror -Wextra -std=gnu99"])
+
+# Checks for programs.
+AC_PROG_CC
+AC_PROG_INSTALL
+AC_PROG_MAKE_SET
+
+# Checks for header files.
+AC_HEADER_DIRENT
+AC_HEADER_STDC
+AC_CHECK_HEADERS([arpa/inet.h fcntl.h netdb.h netinet/in.h stdint.h stdlib.h dnl
+                 string.h sys/socket.h syslog.h unistd.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_TYPE_INT32_T
+AC_TYPE_SIZE_T
+AC_TYPE_SSIZE_T
+AC_TYPE_UINT16_T
+AC_TYPE_UINT32_T
+AC_TYPE_UINT8_T
+
+# Checks for library functions.
+AC_FUNC_REALLOC
+AC_CHECK_FUNCS([memset mkdir regcomp socket strchr strerror strstr dnl
+               strtoul])
+
+AC_CHECK_HEADER([libudev.h],
+               [AC_CHECK_LIB([udev], [udev_new],
+                             [LIBS="$LIBS -ludev"],
+                             [AC_MSG_ERROR([Missing udev library!])])],
+               [AC_MSG_ERROR([Missing /usr/include/libudev.h])])
+
+# Checks for libwrap library.
+AC_MSG_CHECKING([whether to use the libwrap (TCP wrappers) library])
+AC_ARG_WITH([tcp-wrappers],
+           [AS_HELP_STRING([--with-tcp-wrappers],
+                           [use the libwrap (TCP wrappers) library])],
+           dnl [ACTION-IF-GIVEN]
+           [if test "$withval" = "yes"; then
+                    AC_MSG_RESULT([yes])
+                    AC_MSG_CHECKING([for hosts_access in -lwrap])
+                    saved_LIBS="$LIBS"
+                    LIBS="-lwrap $saved_LIBS"
+                    AC_TRY_LINK(
+                      [int hosts_access(); int allow_severity, deny_severity;],
+                      [hosts_access()],
+                      [AC_MSG_RESULT([yes]);
+                       AC_DEFINE([HAVE_LIBWRAP], [1],
+                                 [use tcp wrapper]) wrap_LIB="-lwrap"],
+                      [AC_MSG_RESULT([not found]); exit 1])
+            else
+                    AC_MSG_RESULT([no]);
+            fi],
+           dnl [ACTION-IF-NOT-GIVEN]
+           [AC_MSG_RESULT([(default)])
+            AC_MSG_CHECKING([for hosts_access in -lwrap])
+            saved_LIBS="$LIBS"
+            LIBS="-lwrap $saved_LIBS"
+            AC_TRY_LINK(
+              [int hosts_access(); int allow_severity, deny_severity;],
+              [hosts_access()],
+              [AC_MSG_RESULT([yes]);
+               AC_DEFINE([HAVE_LIBWRAP], [1], [use tcp wrapper])],
+              [AC_MSG_RESULT([no]); LIBS="$saved_LIBS"])])
+
+# Sets directory containing usb.ids.
+AC_ARG_WITH([usbids-dir],
+           [AS_HELP_STRING([--with-usbids-dir=DIR],
+              [where usb.ids is found (default /usr/share/hwdata/)])],
+           [USBIDS_DIR=$withval], [USBIDS_DIR="/usr/share/hwdata/"])
+AC_SUBST([USBIDS_DIR])
+
+# use _FORTIFY_SOURCE
+AC_MSG_CHECKING([whether to use fortify])
+AC_ARG_WITH([fortify],
+           [AS_HELP_STRING([--with-fortify],
+                           [use _FORTIFY_SROUCE option when compiling)])],
+                           dnl [ACTION-IF-GIVEN]
+                           [if test "$withval" = "yes"; then
+                               AC_MSG_RESULT([yes])
+                               CFLAGS="$CFLAGS -D_FORTIFY_SOURCE -O"
+                            else
+                               AC_MSG_RESULT([no])
+                               CFLAGS="$CFLAGS -U_FORTIFY_SOURCE"
+                            fi
+                           ],
+                           dnl [ACTION-IF-NOT-GIVEN]
+                           [AC_MSG_RESULT([default])])
+
+AC_CONFIG_FILES([Makefile libsrc/Makefile src/Makefile])
+AC_OUTPUT
diff --git a/tools/usb/usbip/doc/usbip.8 b/tools/usb/usbip/doc/usbip.8
new file mode 100644 (file)
index 0000000..a6097be
--- /dev/null
@@ -0,0 +1,95 @@
+.TH USBIP "8" "February 2009" "usbip" "System Administration Utilities"
+.SH NAME
+usbip \- manage USB/IP devices
+.SH SYNOPSIS
+.B usbip
+[\fIoptions\fR] <\fIcommand\fR> <\fIargs\fR>
+
+.SH DESCRIPTION
+On a USB/IP server, devices can be listed, bound, and unbound using
+this program.  On a USB/IP client, devices exported by USB/IP servers
+can be listed, attached and detached.
+
+.SH OPTIONS
+.HP
+\fB\-\-debug\fR
+.IP
+Print debugging information.
+.PP
+
+.HP
+\fB\-\-log\fR
+.IP
+Log to syslog.
+.PP
+
+.HP
+\fB\-\-tcp-port PORT\fR
+.IP
+Connect to PORT on remote host (used for attach and list --remote).
+.PP
+
+.SH COMMANDS
+.HP
+\fBversion\fR
+.IP
+Show version and exit.
+.PP
+
+.HP
+\fBhelp\fR [\fIcommand\fR]
+.IP
+Print the program help message, or help on a specific command, and
+then exit.
+.PP
+
+.HP
+\fBattach\fR \-\-remote=<\fIhost\fR> \-\-busid=<\fIbus_id\fR>
+.IP
+Attach a remote USB device.
+.PP
+
+.HP
+\fBdetach\fR \-\-port=<\fIport\fR>
+.IP
+Detach an imported USB device.
+.PP
+
+.HP
+\fBbind\fR \-\-busid=<\fIbusid\fR>
+.IP
+Make a device exportable.
+.PP
+
+.HP
+\fBunbind\fR \-\-busid=<\fIbusid\fR>
+.IP
+Stop exporting a device so it can be used by a local driver.
+.PP
+
+.HP
+\fBlist\fR \-\-remote=<\fIhost\fR>
+.IP
+List USB devices exported by a remote host.
+.PP
+
+.HP
+\fBlist\fR \-\-local
+.IP
+List local USB devices.
+.PP
+
+
+.SH EXAMPLES
+
+    client:# usbip list --remote=server
+        - List exportable usb devices on the server.
+
+    client:# usbip attach --remote=server --busid=1-2
+        - Connect the remote USB device.
+
+    client:# usbip detach --port=0
+        - Detach the usb device.
+
+.SH "SEE ALSO"
+\fBusbipd\fP\fB(8)\fB\fP
diff --git a/tools/usb/usbip/doc/usbipd.8 b/tools/usb/usbip/doc/usbipd.8
new file mode 100644 (file)
index 0000000..ac4635d
--- /dev/null
@@ -0,0 +1,91 @@
+.TH USBIP "8" "February 2009" "usbip" "System Administration Utilities"
+.SH NAME
+usbipd \- USB/IP server daemon
+.SH SYNOPSIS
+.B usbipd
+[\fIoptions\fR]
+
+.SH DESCRIPTION
+.B usbipd
+provides USB/IP clients access to exported USB devices.
+
+Devices have to explicitly be exported using
+.B usbip bind
+before usbipd makes them available to other hosts.
+
+The daemon accepts connections from USB/IP clients
+on TCP port 3240 by default.
+
+.SH OPTIONS
+.HP
+\fB\-4\fR, \fB\-\-ipv4\fR
+.IP
+Bind to IPv4. Default is both.
+.PP
+
+.HP
+\fB\-6\fR, \fB\-\-ipv6\fR
+.IP
+Bind to IPv6. Default is both.
+.PP
+
+.HP
+\fB\-D\fR, \fB\-\-daemon\fR
+.IP
+Run as a daemon process.
+.PP
+
+.HP
+\fB\-d\fR, \fB\-\-debug\fR
+.IP
+Print debugging information.
+.PP
+
+.HP
+\fB\-PFILE\fR, \fB\-\-pid FILE\fR
+.IP
+Write process id to FILE.
+.br
+If no FILE specified, use /var/run/usbipd.pid
+.PP
+
+\fB\-tPORT\fR, \fB\-\-tcp\-port PORT\fR
+.IP
+Listen on TCP/IP port PORT.
+.PP
+
+\fB\-h\fR, \fB\-\-help\fR
+.IP
+Print the program help message and exit.
+.PP
+
+.HP
+\fB\-v\fR, \fB\-\-version\fR
+.IP
+Show version.
+.PP
+
+.SH LIMITATIONS
+
+.B usbipd
+offers no authentication or authorization for USB/IP. Any
+USB/IP client can connect and use exported devices.
+
+.SH EXAMPLES
+
+    server:# modprobe usbip
+
+    server:# usbipd -D
+        - Start usbip daemon.
+
+    server:# usbip list --local
+        - List driver assignments for usb devices.
+
+    server:# usbip bind --busid=1-2
+        - Bind usbip-host.ko to the device of busid 1-2.
+        - A usb device 1-2 is now exportable to other hosts!
+        - Use 'usbip unbind --busid=1-2' when you want to shutdown exporting and use the device locally.
+
+.SH "SEE ALSO"
+\fBusbip\fP\fB(8)\fB\fP
+
diff --git a/tools/usb/usbip/libsrc/Makefile.am b/tools/usb/usbip/libsrc/Makefile.am
new file mode 100644 (file)
index 0000000..7c8f8a4
--- /dev/null
@@ -0,0 +1,8 @@
+libusbip_la_CPPFLAGS = -DUSBIDS_FILE='"@USBIDS_DIR@/usb.ids"'
+libusbip_la_CFLAGS   = @EXTRA_CFLAGS@
+libusbip_la_LDFLAGS  = -version-info @LIBUSBIP_VERSION@
+
+lib_LTLIBRARIES := libusbip.la
+libusbip_la_SOURCES := names.c names.h usbip_host_driver.c usbip_host_driver.h \
+                      usbip_common.c usbip_common.h vhci_driver.c vhci_driver.h \
+                      sysfs_utils.c sysfs_utils.h
diff --git a/tools/usb/usbip/libsrc/list.h b/tools/usb/usbip/libsrc/list.h
new file mode 100644 (file)
index 0000000..8d0c936
--- /dev/null
@@ -0,0 +1,136 @@
+#ifndef _LIST_H
+#define _LIST_H
+
+/* Stripped down implementation of linked list taken
+ * from the Linux Kernel.
+ */
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+       struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+       struct list_head name = LIST_HEAD_INIT(name)
+
+static inline void INIT_LIST_HEAD(struct list_head *list)
+{
+       list->next = list;
+       list->prev = list;
+}
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *new,
+                             struct list_head *prev,
+                             struct list_head *next)
+{
+       next->prev = new;
+       new->next = next;
+       new->prev = prev;
+       prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+       __list_add(new, head, head->next);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head * prev, struct list_head * next)
+{
+       next->prev = prev;
+       prev->next = next;
+}
+
+#define POISON_POINTER_DELTA 0
+#define LIST_POISON1  ((void *) 0x00100100 + POISON_POINTER_DELTA)
+#define LIST_POISON2  ((void *) 0x00200200 + POISON_POINTER_DELTA)
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty() on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void __list_del_entry(struct list_head *entry)
+{
+       __list_del(entry->prev, entry->next);
+}
+
+static inline void list_del(struct list_head *entry)
+{
+       __list_del(entry->prev, entry->next);
+       entry->next = LIST_POISON1;
+       entry->prev = LIST_POISON2;
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr:       the &struct list_head pointer.
+ * @type:      the type of the struct this is embedded in.
+ * @member:    the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+       container_of(ptr, type, member)
+/**
+ * list_for_each       -       iterate over a list
+ * @pos:       the &struct list_head to use as a loop cursor.
+ * @head:      the head for your list.
+ */
+#define list_for_each(pos, head) \
+       for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_safe - iterate over a list safe against removal of list entry
+ * @pos:       the &struct list_head to use as a loop cursor.
+ * @n:         another &struct list_head to use as temporary storage
+ * @head:      the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+       for (pos = (head)->next, n = pos->next; pos != (head); \
+               pos = n, n = pos->next)
+
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ * @ptr:       the pointer to the member.
+ * @type:      the type of the container struct this is embedded in.
+ * @member:    the name of the member within the struct.
+ *
+ */
+#define container_of(ptr, type, member) ({                     \
+       const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
+       (type *)( (char *)__mptr - offsetof(type,member) );})
+
+#endif
diff --git a/tools/usb/usbip/libsrc/names.c b/tools/usb/usbip/libsrc/names.c
new file mode 100644 (file)
index 0000000..81ff852
--- /dev/null
@@ -0,0 +1,504 @@
+/*
+ *      names.c  --  USB name database manipulation routines
+ *
+ *      Copyright (C) 1999, 2000  Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ *      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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ *
+ *
+ *
+ *     Copyright (C) 2005 Takahiro Hirofuchi
+ *             - names_deinit() is added.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include "names.h"
+#include "usbip_common.h"
+
+struct vendor {
+       struct vendor *next;
+       u_int16_t vendorid;
+       char name[1];
+};
+
+struct product {
+       struct product *next;
+       u_int16_t vendorid, productid;
+       char name[1];
+};
+
+struct class {
+       struct class *next;
+       u_int8_t classid;
+       char name[1];
+};
+
+struct subclass {
+       struct subclass *next;
+       u_int8_t classid, subclassid;
+       char name[1];
+};
+
+struct protocol {
+       struct protocol *next;
+       u_int8_t classid, subclassid, protocolid;
+       char name[1];
+};
+
+struct genericstrtable {
+       struct genericstrtable *next;
+       unsigned int num;
+       char name[1];
+};
+
+
+#define HASH1  0x10
+#define HASH2  0x02
+#define HASHSZ 16
+
+static unsigned int hashnum(unsigned int num)
+{
+       unsigned int mask1 = HASH1 << 27, mask2 = HASH2 << 27;
+
+       for (; mask1 >= HASH1; mask1 >>= 1, mask2 >>= 1)
+               if (num & mask1)
+                       num ^= mask2;
+       return num & (HASHSZ-1);
+}
+
+
+static struct vendor *vendors[HASHSZ] = { NULL, };
+static struct product *products[HASHSZ] = { NULL, };
+static struct class *classes[HASHSZ] = { NULL, };
+static struct subclass *subclasses[HASHSZ] = { NULL, };
+static struct protocol *protocols[HASHSZ] = { NULL, };
+
+const char *names_vendor(u_int16_t vendorid)
+{
+       struct vendor *v;
+
+       v = vendors[hashnum(vendorid)];
+       for (; v; v = v->next)
+               if (v->vendorid == vendorid)
+                       return v->name;
+       return NULL;
+}
+
+const char *names_product(u_int16_t vendorid, u_int16_t productid)
+{
+       struct product *p;
+
+       p = products[hashnum((vendorid << 16) | productid)];
+       for (; p; p = p->next)
+               if (p->vendorid == vendorid && p->productid == productid)
+                       return p->name;
+       return NULL;
+}
+
+const char *names_class(u_int8_t classid)
+{
+       struct class *c;
+
+       c = classes[hashnum(classid)];
+       for (; c; c = c->next)
+               if (c->classid == classid)
+                       return c->name;
+       return NULL;
+}
+
+const char *names_subclass(u_int8_t classid, u_int8_t subclassid)
+{
+       struct subclass *s;
+
+       s = subclasses[hashnum((classid << 8) | subclassid)];
+       for (; s; s = s->next)
+               if (s->classid == classid && s->subclassid == subclassid)
+                       return s->name;
+       return NULL;
+}
+
+const char *names_protocol(u_int8_t classid, u_int8_t subclassid,
+                          u_int8_t protocolid)
+{
+       struct protocol *p;
+
+       p = protocols[hashnum((classid << 16) | (subclassid << 8)
+                             | protocolid)];
+       for (; p; p = p->next)
+               if (p->classid == classid && p->subclassid == subclassid &&
+                   p->protocolid == protocolid)
+                       return p->name;
+       return NULL;
+}
+
+/* add a cleanup function by takahiro */
+struct pool {
+       struct pool *next;
+       void *mem;
+};
+
+static struct pool *pool_head;
+
+static void *my_malloc(size_t size)
+{
+       struct pool *p;
+
+       p = calloc(1, sizeof(struct pool));
+       if (!p)
+               return NULL;
+
+       p->mem = calloc(1, size);
+       if (!p->mem) {
+               free(p);
+               return NULL;
+       }
+
+       p->next = pool_head;
+       pool_head = p;
+
+       return p->mem;
+}
+
+void names_free(void)
+{
+       struct pool *pool;
+
+       if (!pool_head)
+               return;
+
+       for (pool = pool_head; pool != NULL; ) {
+               struct pool *tmp;
+
+               if (pool->mem)
+                       free(pool->mem);
+
+               tmp = pool;
+               pool = pool->next;
+               free(tmp);
+       }
+}
+
+static int new_vendor(const char *name, u_int16_t vendorid)
+{
+       struct vendor *v;
+       unsigned int h = hashnum(vendorid);
+
+       v = vendors[h];
+       for (; v; v = v->next)
+               if (v->vendorid == vendorid)
+                       return -1;
+       v = my_malloc(sizeof(struct vendor) + strlen(name));
+       if (!v)
+               return -1;
+       strcpy(v->name, name);
+       v->vendorid = vendorid;
+       v->next = vendors[h];
+       vendors[h] = v;
+       return 0;
+}
+
+static int new_product(const char *name, u_int16_t vendorid,
+                      u_int16_t productid)
+{
+       struct product *p;
+       unsigned int h = hashnum((vendorid << 16) | productid);
+
+       p = products[h];
+       for (; p; p = p->next)
+               if (p->vendorid == vendorid && p->productid == productid)
+                       return -1;
+       p = my_malloc(sizeof(struct product) + strlen(name));
+       if (!p)
+               return -1;
+       strcpy(p->name, name);
+       p->vendorid = vendorid;
+       p->productid = productid;
+       p->next = products[h];
+       products[h] = p;
+       return 0;
+}
+
+static int new_class(const char *name, u_int8_t classid)
+{
+       struct class *c;
+       unsigned int h = hashnum(classid);
+
+       c = classes[h];
+       for (; c; c = c->next)
+               if (c->classid == classid)
+                       return -1;
+       c = my_malloc(sizeof(struct class) + strlen(name));
+       if (!c)
+               return -1;
+       strcpy(c->name, name);
+       c->classid = classid;
+       c->next = classes[h];
+       classes[h] = c;
+       return 0;
+}
+
+static int new_subclass(const char *name, u_int8_t classid, u_int8_t subclassid)
+{
+       struct subclass *s;
+       unsigned int h = hashnum((classid << 8) | subclassid);
+
+       s = subclasses[h];
+       for (; s; s = s->next)
+               if (s->classid == classid && s->subclassid == subclassid)
+                       return -1;
+       s = my_malloc(sizeof(struct subclass) + strlen(name));
+       if (!s)
+               return -1;
+       strcpy(s->name, name);
+       s->classid = classid;
+       s->subclassid = subclassid;
+       s->next = subclasses[h];
+       subclasses[h] = s;
+       return 0;
+}
+
+static int new_protocol(const char *name, u_int8_t classid, u_int8_t subclassid,
+                       u_int8_t protocolid)
+{
+       struct protocol *p;
+       unsigned int h = hashnum((classid << 16) | (subclassid << 8)
+                                | protocolid);
+
+       p = protocols[h];
+       for (; p; p = p->next)
+               if (p->classid == classid && p->subclassid == subclassid
+                   && p->protocolid == protocolid)
+                       return -1;
+       p = my_malloc(sizeof(struct protocol) + strlen(name));
+       if (!p)
+               return -1;
+       strcpy(p->name, name);
+       p->classid = classid;
+       p->subclassid = subclassid;
+       p->protocolid = protocolid;
+       p->next = protocols[h];
+       protocols[h] = p;
+       return 0;
+}
+
+static void parse(FILE *f)
+{
+       char buf[512], *cp;
+       unsigned int linectr = 0;
+       int lastvendor = -1;
+       int lastclass = -1;
+       int lastsubclass = -1;
+       int lasthut = -1;
+       int lastlang = -1;
+       unsigned int u;
+
+       while (fgets(buf, sizeof(buf), f)) {
+               linectr++;
+               /* remove line ends */
+               cp = strchr(buf, '\r');
+               if (cp)
+                       *cp = 0;
+               cp = strchr(buf, '\n');
+               if (cp)
+                       *cp = 0;
+               if (buf[0] == '#' || !buf[0])
+                       continue;
+               cp = buf;
+               if (buf[0] == 'P' && buf[1] == 'H' && buf[2] == 'Y' &&
+                   buf[3] == 'S' && buf[4] == 'D' &&
+                   buf[5] == 'E' && buf[6] == 'S' && /*isspace(buf[7])*/
+                   buf[7] == ' ') {
+                       continue;
+               }
+               if (buf[0] == 'P' && buf[1] == 'H' &&
+                   buf[2] == 'Y' && /*isspace(buf[3])*/ buf[3] == ' ') {
+                       continue;
+               }
+               if (buf[0] == 'B' && buf[1] == 'I' && buf[2] == 'A' &&
+                   buf[3] == 'S' && /*isspace(buf[4])*/ buf[4] == ' ') {
+                       continue;
+               }
+               if (buf[0] == 'L' && /*isspace(buf[1])*/ buf[1] == ' ') {
+                       lasthut = lastclass = lastvendor = lastsubclass = -1;
+                       /*
+                        * set 1 as pseudo-id to indicate that the parser is
+                        * in a `L' section.
+                        */
+                       lastlang = 1;
+                       continue;
+               }
+               if (buf[0] == 'C' && /*isspace(buf[1])*/ buf[1] == ' ') {
+                       /* class spec */
+                       cp = buf+2;
+                       while (isspace(*cp))
+                               cp++;
+                       if (!isxdigit(*cp)) {
+                               err("Invalid class spec at line %u", linectr);
+                               continue;
+                       }
+                       u = strtoul(cp, &cp, 16);
+                       while (isspace(*cp))
+                               cp++;
+                       if (!*cp) {
+                               err("Invalid class spec at line %u", linectr);
+                               continue;
+                       }
+                       if (new_class(cp, u))
+                               err("Duplicate class spec at line %u class %04x %s",
+                                   linectr, u, cp);
+                       dbg("line %5u class %02x %s", linectr, u, cp);
+                       lasthut = lastlang = lastvendor = lastsubclass = -1;
+                       lastclass = u;
+                       continue;
+               }
+               if (buf[0] == 'A' && buf[1] == 'T' && isspace(buf[2])) {
+                       /* audio terminal type spec */
+                       continue;
+               }
+               if (buf[0] == 'H' && buf[1] == 'C' && buf[2] == 'C'
+                   && isspace(buf[3])) {
+                       /* HID Descriptor bCountryCode */
+                       continue;
+               }
+               if (isxdigit(*cp)) {
+                       /* vendor */
+                       u = strtoul(cp, &cp, 16);
+                       while (isspace(*cp))
+                               cp++;
+                       if (!*cp) {
+                               err("Invalid vendor spec at line %u", linectr);
+                               continue;
+                       }
+                       if (new_vendor(cp, u))
+                               err("Duplicate vendor spec at line %u vendor %04x %s",
+                                   linectr, u, cp);
+                       dbg("line %5u vendor %04x %s", linectr, u, cp);
+                       lastvendor = u;
+                       lasthut = lastlang = lastclass = lastsubclass = -1;
+                       continue;
+               }
+               if (buf[0] == '\t' && isxdigit(buf[1])) {
+                       /* product or subclass spec */
+                       u = strtoul(buf+1, &cp, 16);
+                       while (isspace(*cp))
+                               cp++;
+                       if (!*cp) {
+                               err("Invalid product/subclass spec at line %u",
+                                   linectr);
+                               continue;
+                       }
+                       if (lastvendor != -1) {
+                               if (new_product(cp, lastvendor, u))
+                                       err("Duplicate product spec at line %u product %04x:%04x %s",
+                                           linectr, lastvendor, u, cp);
+                               dbg("line %5u product %04x:%04x %s", linectr,
+                                   lastvendor, u, cp);
+                               continue;
+                       }
+                       if (lastclass != -1) {
+                               if (new_subclass(cp, lastclass, u))
+                                       err("Duplicate subclass spec at line %u class %02x:%02x %s",
+                                           linectr, lastclass, u, cp);
+                               dbg("line %5u subclass %02x:%02x %s", linectr,
+                                   lastclass, u, cp);
+                               lastsubclass = u;
+                               continue;
+                       }
+                       if (lasthut != -1) {
+                               /* do not store hut */
+                               continue;
+                       }
+                       if (lastlang != -1) {
+                               /* do not store langid */
+                               continue;
+                       }
+                       err("Product/Subclass spec without prior Vendor/Class spec at line %u",
+                           linectr);
+                       continue;
+               }
+               if (buf[0] == '\t' && buf[1] == '\t' && isxdigit(buf[2])) {
+                       /* protocol spec */
+                       u = strtoul(buf+2, &cp, 16);
+                       while (isspace(*cp))
+                               cp++;
+                       if (!*cp) {
+                               err("Invalid protocol spec at line %u",
+                                   linectr);
+                               continue;
+                       }
+                       if (lastclass != -1 && lastsubclass != -1) {
+                               if (new_protocol(cp, lastclass, lastsubclass,
+                                                u))
+                                       err("Duplicate protocol spec at line %u class %02x:%02x:%02x %s",
+                                           linectr, lastclass, lastsubclass,
+                                           u, cp);
+                               dbg("line %5u protocol %02x:%02x:%02x %s",
+                                   linectr, lastclass, lastsubclass, u, cp);
+                               continue;
+                       }
+                       err("Protocol spec without prior Class and Subclass spec at line %u",
+                           linectr);
+                       continue;
+               }
+               if (buf[0] == 'H' && buf[1] == 'I' &&
+                   buf[2] == 'D' && /*isspace(buf[3])*/ buf[3] == ' ') {
+                       continue;
+               }
+               if (buf[0] == 'H' && buf[1] == 'U' &&
+                   buf[2] == 'T' && /*isspace(buf[3])*/ buf[3] == ' ') {
+                       lastlang = lastclass = lastvendor = lastsubclass = -1;
+                       /*
+                        * set 1 as pseudo-id to indicate that the parser is
+                        * in a `HUT' section.
+                        */
+                       lasthut = 1;
+                       continue;
+               }
+               if (buf[0] == 'R' && buf[1] == ' ')
+                       continue;
+
+               if (buf[0] == 'V' && buf[1] == 'T')
+                       continue;
+
+               err("Unknown line at line %u", linectr);
+       }
+}
+
+
+int names_init(char *n)
+{
+       FILE *f;
+
+       f = fopen(n, "r");
+       if (!f)
+               return errno;
+
+       parse(f);
+       fclose(f);
+       return 0;
+}
diff --git a/tools/usb/usbip/libsrc/names.h b/tools/usb/usbip/libsrc/names.h
new file mode 100644 (file)
index 0000000..6809265
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ *      names.h  --  USB name database manipulation routines
+ *
+ *      Copyright (C) 1999, 2000  Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ *      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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ *
+ *     Copyright (C) 2005 Takahiro Hirofuchi
+ *            - names_free() is added.
+ */
+
+#ifndef _NAMES_H
+#define _NAMES_H
+
+#include <sys/types.h>
+
+/* used by usbip_common.c */
+extern const char *names_vendor(u_int16_t vendorid);
+extern const char *names_product(u_int16_t vendorid, u_int16_t productid);
+extern const char *names_class(u_int8_t classid);
+extern const char *names_subclass(u_int8_t classid, u_int8_t subclassid);
+extern const char *names_protocol(u_int8_t classid, u_int8_t subclassid,
+                                 u_int8_t protocolid);
+extern int  names_init(char *n);
+extern void names_free(void);
+
+#endif /* _NAMES_H */
diff --git a/tools/usb/usbip/libsrc/sysfs_utils.c b/tools/usb/usbip/libsrc/sysfs_utils.c
new file mode 100644 (file)
index 0000000..36ac88e
--- /dev/null
@@ -0,0 +1,31 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "sysfs_utils.h"
+#include "usbip_common.h"
+
+int write_sysfs_attribute(const char *attr_path, const char *new_value,
+                         size_t len)
+{
+       int fd;
+       int length;
+
+       fd = open(attr_path, O_WRONLY);
+       if (fd < 0) {
+               dbg("error opening attribute %s", attr_path);
+               return -1;
+       }
+
+       length = write(fd, new_value, len);
+       if (length < 0) {
+               dbg("error writing to attribute %s", attr_path);
+               close(fd);
+               return -1;
+       }
+
+       close(fd);
+
+       return 0;
+}
diff --git a/tools/usb/usbip/libsrc/sysfs_utils.h b/tools/usb/usbip/libsrc/sysfs_utils.h
new file mode 100644 (file)
index 0000000..32ac1d1
--- /dev/null
@@ -0,0 +1,8 @@
+
+#ifndef __SYSFS_UTILS_H
+#define __SYSFS_UTILS_H
+
+int write_sysfs_attribute(const char *attr_path, const char *new_value,
+                         size_t len);
+
+#endif
diff --git a/tools/usb/usbip/libsrc/usbip_common.c b/tools/usb/usbip/libsrc/usbip_common.c
new file mode 100644 (file)
index 0000000..ac73710
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2005-2007 Takahiro Hirofuchi
+ */
+
+#include <libudev.h>
+#include "usbip_common.h"
+#include "names.h"
+
+#undef  PROGNAME
+#define PROGNAME "libusbip"
+
+int usbip_use_syslog;
+int usbip_use_stderr;
+int usbip_use_debug;
+
+extern struct udev *udev_context;
+
+struct speed_string {
+       int num;
+       char *speed;
+       char *desc;
+};
+
+static const struct speed_string speed_strings[] = {
+       { USB_SPEED_UNKNOWN, "unknown", "Unknown Speed"},
+       { USB_SPEED_LOW,  "1.5", "Low Speed(1.5Mbps)"  },
+       { USB_SPEED_FULL, "12",  "Full Speed(12Mbps)" },
+       { USB_SPEED_HIGH, "480", "High Speed(480Mbps)" },
+       { USB_SPEED_WIRELESS, "53.3-480", "Wireless"},
+       { USB_SPEED_SUPER, "5000", "Super Speed(5000Mbps)" },
+       { 0, NULL, NULL }
+};
+
+struct portst_string {
+       int num;
+       char *desc;
+};
+
+static struct portst_string portst_strings[] = {
+       { SDEV_ST_AVAILABLE,    "Device Available" },
+       { SDEV_ST_USED,         "Device in Use" },
+       { SDEV_ST_ERROR,        "Device Error"},
+       { VDEV_ST_NULL,         "Port Available"},
+       { VDEV_ST_NOTASSIGNED,  "Port Initializing"},
+       { VDEV_ST_USED,         "Port in Use"},
+       { VDEV_ST_ERROR,        "Port Error"},
+       { 0, NULL}
+};
+
+const char *usbip_status_string(int32_t status)
+{
+       for (int i = 0; portst_strings[i].desc != NULL; i++)
+               if (portst_strings[i].num == status)
+                       return portst_strings[i].desc;
+
+       return "Unknown Status";
+}
+
+const char *usbip_speed_string(int num)
+{
+       for (int i = 0; speed_strings[i].speed != NULL; i++)
+               if (speed_strings[i].num == num)
+                       return speed_strings[i].desc;
+
+       return "Unknown Speed";
+}
+
+
+#define DBG_UDEV_INTEGER(name)\
+       dbg("%-20s = %x", to_string(name), (int) udev->name)
+
+#define DBG_UINF_INTEGER(name)\
+       dbg("%-20s = %x", to_string(name), (int) uinf->name)
+
+void dump_usb_interface(struct usbip_usb_interface *uinf)
+{
+       char buff[100];
+
+       usbip_names_get_class(buff, sizeof(buff),
+                       uinf->bInterfaceClass,
+                       uinf->bInterfaceSubClass,
+                       uinf->bInterfaceProtocol);
+       dbg("%-20s = %s", "Interface(C/SC/P)", buff);
+}
+
+void dump_usb_device(struct usbip_usb_device *udev)
+{
+       char buff[100];
+
+       dbg("%-20s = %s", "path",  udev->path);
+       dbg("%-20s = %s", "busid", udev->busid);
+
+       usbip_names_get_class(buff, sizeof(buff),
+                       udev->bDeviceClass,
+                       udev->bDeviceSubClass,
+                       udev->bDeviceProtocol);
+       dbg("%-20s = %s", "Device(C/SC/P)", buff);
+
+       DBG_UDEV_INTEGER(bcdDevice);
+
+       usbip_names_get_product(buff, sizeof(buff),
+                       udev->idVendor,
+                       udev->idProduct);
+       dbg("%-20s = %s", "Vendor/Product", buff);
+
+       DBG_UDEV_INTEGER(bNumConfigurations);
+       DBG_UDEV_INTEGER(bNumInterfaces);
+
+       dbg("%-20s = %s", "speed",
+                       usbip_speed_string(udev->speed));
+
+       DBG_UDEV_INTEGER(busnum);
+       DBG_UDEV_INTEGER(devnum);
+}
+
+
+int read_attr_value(struct udev_device *dev, const char *name,
+                   const char *format)
+{
+       const char *attr;
+       int num = 0;
+       int ret;
+
+       attr = udev_device_get_sysattr_value(dev, name);
+       if (!attr) {
+               err("udev_device_get_sysattr_value failed");
+               goto err;
+       }
+
+       /* The client chooses the device configuration
+        * when attaching it so right after being bound
+        * to usbip-host on the server the device will
+        * have no configuration.
+        * Therefore, attributes such as bConfigurationValue
+        * and bNumInterfaces will not exist and sscanf will
+        * fail. Check for these cases and don't treat them
+        * as errors.
+        */
+
+       ret = sscanf(attr, format, &num);
+       if (ret < 1) {
+               if (strcmp(name, "bConfigurationValue") &&
+                               strcmp(name, "bNumInterfaces")) {
+                       err("sscanf failed for attribute %s", name);
+                       goto err;
+               }
+       }
+
+err:
+
+       return num;
+}
+
+
+int read_attr_speed(struct udev_device *dev)
+{
+       const char *speed;
+
+       speed = udev_device_get_sysattr_value(dev, "speed");
+       if (!speed) {
+               err("udev_device_get_sysattr_value failed");
+               goto err;
+       }
+
+       for (int i = 0; speed_strings[i].speed != NULL; i++) {
+               if (!strcmp(speed, speed_strings[i].speed))
+                       return speed_strings[i].num;
+       }
+
+err:
+
+       return USB_SPEED_UNKNOWN;
+}
+
+#define READ_ATTR(object, type, dev, name, format)                           \
+       do {                                                                  \
+               (object)->name = (type) read_attr_value(dev, to_string(name), \
+                                                       format);              \
+       } while (0)
+
+
+int read_usb_device(struct udev_device *sdev, struct usbip_usb_device *udev)
+{
+       uint32_t busnum, devnum;
+       const char *path, *name;
+
+       READ_ATTR(udev, uint8_t,  sdev, bDeviceClass,           "%02x\n");
+       READ_ATTR(udev, uint8_t,  sdev, bDeviceSubClass,        "%02x\n");
+       READ_ATTR(udev, uint8_t,  sdev, bDeviceProtocol,        "%02x\n");
+
+       READ_ATTR(udev, uint16_t, sdev, idVendor,               "%04x\n");
+       READ_ATTR(udev, uint16_t, sdev, idProduct,              "%04x\n");
+       READ_ATTR(udev, uint16_t, sdev, bcdDevice,              "%04x\n");
+
+       READ_ATTR(udev, uint8_t,  sdev, bConfigurationValue,    "%02x\n");
+       READ_ATTR(udev, uint8_t,  sdev, bNumConfigurations,     "%02x\n");
+       READ_ATTR(udev, uint8_t,  sdev, bNumInterfaces,         "%02x\n");
+
+       READ_ATTR(udev, uint8_t,  sdev, devnum,                 "%d\n");
+       udev->speed = read_attr_speed(sdev);
+
+       path = udev_device_get_syspath(sdev);
+       name = udev_device_get_sysname(sdev);
+
+       strncpy(udev->path,  path,  SYSFS_PATH_MAX);
+       strncpy(udev->busid, name, SYSFS_BUS_ID_SIZE);
+
+       sscanf(name, "%u-%u", &busnum, &devnum);
+       udev->busnum = busnum;
+
+       return 0;
+}
+
+int read_usb_interface(struct usbip_usb_device *udev, int i,
+                      struct usbip_usb_interface *uinf)
+{
+       char busid[SYSFS_BUS_ID_SIZE];
+       struct udev_device *sif;
+
+       sprintf(busid, "%s:%d.%d", udev->busid, udev->bConfigurationValue, i);
+
+       sif = udev_device_new_from_subsystem_sysname(udev_context, "usb", busid);
+       if (!sif) {
+               err("udev_device_new_from_subsystem_sysname %s failed", busid);
+               return -1;
+       }
+
+       READ_ATTR(uinf, uint8_t,  sif, bInterfaceClass,         "%02x\n");
+       READ_ATTR(uinf, uint8_t,  sif, bInterfaceSubClass,      "%02x\n");
+       READ_ATTR(uinf, uint8_t,  sif, bInterfaceProtocol,      "%02x\n");
+
+       return 0;
+}
+
+int usbip_names_init(char *f)
+{
+       return names_init(f);
+}
+
+void usbip_names_free(void)
+{
+       names_free();
+}
+
+void usbip_names_get_product(char *buff, size_t size, uint16_t vendor,
+                            uint16_t product)
+{
+       const char *prod, *vend;
+
+       prod = names_product(vendor, product);
+       if (!prod)
+               prod = "unknown product";
+
+
+       vend = names_vendor(vendor);
+       if (!vend)
+               vend = "unknown vendor";
+
+       snprintf(buff, size, "%s : %s (%04x:%04x)", vend, prod, vendor, product);
+}
+
+void usbip_names_get_class(char *buff, size_t size, uint8_t class,
+                          uint8_t subclass, uint8_t protocol)
+{
+       const char *c, *s, *p;
+
+       if (class == 0 && subclass == 0 && protocol == 0) {
+               snprintf(buff, size, "(Defined at Interface level) (%02x/%02x/%02x)", class, subclass, protocol);
+               return;
+       }
+
+       p = names_protocol(class, subclass, protocol);
+       if (!p)
+               p = "unknown protocol";
+
+       s = names_subclass(class, subclass);
+       if (!s)
+               s = "unknown subclass";
+
+       c = names_class(class);
+       if (!c)
+               c = "unknown class";
+
+       snprintf(buff, size, "%s / %s / %s (%02x/%02x/%02x)", c, s, p, class, subclass, protocol);
+}
diff --git a/tools/usb/usbip/libsrc/usbip_common.h b/tools/usb/usbip/libsrc/usbip_common.h
new file mode 100644 (file)
index 0000000..5a0e95e
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2005-2007 Takahiro Hirofuchi
+ */
+
+#ifndef __USBIP_COMMON_H
+#define __USBIP_COMMON_H
+
+#include <libudev.h>
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <syslog.h>
+#include <unistd.h>
+#include <linux/usb/ch9.h>
+#include "../../uapi/usbip.h"
+
+#ifndef USBIDS_FILE
+#define USBIDS_FILE "/usr/share/hwdata/usb.ids"
+#endif
+
+#ifndef VHCI_STATE_PATH
+#define VHCI_STATE_PATH "/var/run/vhci_hcd"
+#endif
+
+/* kernel module names */
+#define USBIP_CORE_MOD_NAME    "usbip-core"
+#define USBIP_HOST_DRV_NAME    "usbip-host"
+#define USBIP_VHCI_DRV_NAME    "vhci_hcd"
+
+/* sysfs constants */
+#define SYSFS_MNT_PATH         "/sys"
+#define SYSFS_BUS_NAME         "bus"
+#define SYSFS_BUS_TYPE         "usb"
+#define SYSFS_DRIVERS_NAME     "drivers"
+
+#define SYSFS_PATH_MAX         256
+#define SYSFS_BUS_ID_SIZE      32
+
+extern int usbip_use_syslog;
+extern int usbip_use_stderr;
+extern int usbip_use_debug ;
+
+#define PROGNAME "usbip"
+
+#define pr_fmt(fmt)    "%s: %s: " fmt "\n", PROGNAME
+#define dbg_fmt(fmt)   pr_fmt("%s:%d:[%s] " fmt), "debug",     \
+                       __FILE__, __LINE__, __func__
+
+#define err(fmt, args...)                                              \
+       do {                                                            \
+               if (usbip_use_syslog) {                                 \
+                       syslog(LOG_ERR, pr_fmt(fmt), "error", ##args);  \
+               }                                                       \
+               if (usbip_use_stderr) {                                 \
+                       fprintf(stderr, pr_fmt(fmt), "error", ##args);  \
+               }                                                       \
+       } while (0)
+
+#define info(fmt, args...)                                             \
+       do {                                                            \
+               if (usbip_use_syslog) {                                 \
+                       syslog(LOG_INFO, pr_fmt(fmt), "info", ##args);  \
+               }                                                       \
+               if (usbip_use_stderr) {                                 \
+                       fprintf(stderr, pr_fmt(fmt), "info", ##args);   \
+               }                                                       \
+       } while (0)
+
+#define dbg(fmt, args...)                                              \
+       do {                                                            \
+       if (usbip_use_debug) {                                          \
+               if (usbip_use_syslog) {                                 \
+                       syslog(LOG_DEBUG, dbg_fmt(fmt), ##args);        \
+               }                                                       \
+               if (usbip_use_stderr) {                                 \
+                       fprintf(stderr, dbg_fmt(fmt), ##args);          \
+               }                                                       \
+       }                                                               \
+       } while (0)
+
+#define BUG()                                          \
+       do {                                            \
+               err("sorry, it's a bug!");              \
+               abort();                                \
+       } while (0)
+
+struct usbip_usb_interface {
+       uint8_t bInterfaceClass;
+       uint8_t bInterfaceSubClass;
+       uint8_t bInterfaceProtocol;
+       uint8_t padding;        /* alignment */
+} __attribute__((packed));
+
+struct usbip_usb_device {
+       char path[SYSFS_PATH_MAX];
+       char busid[SYSFS_BUS_ID_SIZE];
+
+       uint32_t busnum;
+       uint32_t devnum;
+       uint32_t speed;
+
+       uint16_t idVendor;
+       uint16_t idProduct;
+       uint16_t bcdDevice;
+
+       uint8_t bDeviceClass;
+       uint8_t bDeviceSubClass;
+       uint8_t bDeviceProtocol;
+       uint8_t bConfigurationValue;
+       uint8_t bNumConfigurations;
+       uint8_t bNumInterfaces;
+} __attribute__((packed));
+
+#define to_string(s)   #s
+
+void dump_usb_interface(struct usbip_usb_interface *);
+void dump_usb_device(struct usbip_usb_device *);
+int read_usb_device(struct udev_device *sdev, struct usbip_usb_device *udev);
+int read_attr_value(struct udev_device *dev, const char *name,
+                   const char *format);
+int read_usb_interface(struct usbip_usb_device *udev, int i,
+                      struct usbip_usb_interface *uinf);
+
+const char *usbip_speed_string(int num);
+const char *usbip_status_string(int32_t status);
+
+int usbip_names_init(char *);
+void usbip_names_free(void);
+void usbip_names_get_product(char *buff, size_t size, uint16_t vendor,
+                            uint16_t product);
+void usbip_names_get_class(char *buff, size_t size, uint8_t class,
+                          uint8_t subclass, uint8_t protocol);
+
+#endif /* __USBIP_COMMON_H */
diff --git a/tools/usb/usbip/libsrc/usbip_host_driver.c b/tools/usb/usbip/libsrc/usbip_host_driver.c
new file mode 100644 (file)
index 0000000..bef08d5
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
+ *               2005-2007 Takahiro Hirofuchi
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <errno.h>
+#include <unistd.h>
+
+#include <libudev.h>
+
+#include "usbip_common.h"
+#include "usbip_host_driver.h"
+#include "list.h"
+#include "sysfs_utils.h"
+
+#undef  PROGNAME
+#define PROGNAME "libusbip"
+
+struct usbip_host_driver *host_driver;
+struct udev *udev_context;
+
+static int32_t read_attr_usbip_status(struct usbip_usb_device *udev)
+{
+       char status_attr_path[SYSFS_PATH_MAX];
+       int fd;
+       int length;
+       char status;
+       int value = 0;
+
+       snprintf(status_attr_path, SYSFS_PATH_MAX, "%s/usbip_status",
+                udev->path);
+
+       fd = open(status_attr_path, O_RDONLY);
+       if (fd < 0) {
+               err("error opening attribute %s", status_attr_path);
+               return -1;
+       }
+
+       length = read(fd, &status, 1);
+       if (length < 0) {
+               err("error reading attribute %s", status_attr_path);
+               close(fd);
+               return -1;
+       }
+
+       value = atoi(&status);
+
+       return value;
+}
+
+static
+struct usbip_exported_device *usbip_exported_device_new(const char *sdevpath)
+{
+       struct usbip_exported_device *edev = NULL;
+       struct usbip_exported_device *edev_old;
+       size_t size;
+       int i;
+
+       edev = calloc(1, sizeof(struct usbip_exported_device));
+
+       edev->sudev = udev_device_new_from_syspath(udev_context, sdevpath);
+       if (!edev->sudev) {
+               err("udev_device_new_from_syspath: %s", sdevpath);
+               goto err;
+       }
+
+       read_usb_device(edev->sudev, &edev->udev);
+
+       edev->status = read_attr_usbip_status(&edev->udev);
+       if (edev->status < 0)
+               goto err;
+
+       /* reallocate buffer to include usb interface data */
+       size = sizeof(struct usbip_exported_device) +
+               edev->udev.bNumInterfaces * sizeof(struct usbip_usb_interface);
+
+       edev_old = edev;
+       edev = realloc(edev, size);
+       if (!edev) {
+               edev = edev_old;
+               dbg("realloc failed");
+               goto err;
+       }
+
+       for (i = 0; i < edev->udev.bNumInterfaces; i++)
+               read_usb_interface(&edev->udev, i, &edev->uinf[i]);
+
+       return edev;
+err:
+       if (edev->sudev)
+               udev_device_unref(edev->sudev);
+       if (edev)
+               free(edev);
+
+       return NULL;
+}
+
+static int refresh_exported_devices(void)
+{
+       struct usbip_exported_device *edev;
+       struct udev_enumerate *enumerate;
+       struct udev_list_entry *devices, *dev_list_entry;
+       struct udev_device *dev;
+       const char *path;
+       const char *driver;
+
+       enumerate = udev_enumerate_new(udev_context);
+       udev_enumerate_add_match_subsystem(enumerate, "usb");
+       udev_enumerate_scan_devices(enumerate);
+
+       devices = udev_enumerate_get_list_entry(enumerate);
+
+       udev_list_entry_foreach(dev_list_entry, devices) {
+               path = udev_list_entry_get_name(dev_list_entry);
+               dev = udev_device_new_from_syspath(udev_context, path);
+               if (dev == NULL)
+                       continue;
+
+               /* Check whether device uses usbip-host driver. */
+               driver = udev_device_get_driver(dev);
+               if (driver != NULL && !strcmp(driver, USBIP_HOST_DRV_NAME)) {
+                       edev = usbip_exported_device_new(path);
+                       if (!edev) {
+                               dbg("usbip_exported_device_new failed");
+                               continue;
+                       }
+
+                       list_add(&edev->node, &host_driver->edev_list);
+                       host_driver->ndevs++;
+               }
+       }
+
+       return 0;
+}
+
+static void usbip_exported_device_destroy(void)
+{
+       struct list_head *i, *tmp;
+       struct usbip_exported_device *edev;
+
+       list_for_each_safe(i, tmp, &host_driver->edev_list) {
+               edev = list_entry(i, struct usbip_exported_device, node);
+               list_del(i);
+               free(edev);
+       }
+}
+
+int usbip_host_driver_open(void)
+{
+       int rc;
+
+       udev_context = udev_new();
+       if (!udev_context) {
+               err("udev_new failed");
+               return -1;
+       }
+
+       host_driver = calloc(1, sizeof(*host_driver));
+
+       host_driver->ndevs = 0;
+       INIT_LIST_HEAD(&host_driver->edev_list);
+
+       rc = refresh_exported_devices();
+       if (rc < 0)
+               goto err_free_host_driver;
+
+       return 0;
+
+err_free_host_driver:
+       free(host_driver);
+       host_driver = NULL;
+
+       udev_unref(udev_context);
+
+       return -1;
+}
+
+void usbip_host_driver_close(void)
+{
+       if (!host_driver)
+               return;
+
+       usbip_exported_device_destroy();
+
+       free(host_driver);
+       host_driver = NULL;
+
+       udev_unref(udev_context);
+}
+
+int usbip_host_refresh_device_list(void)
+{
+       int rc;
+
+       usbip_exported_device_destroy();
+
+       host_driver->ndevs = 0;
+       INIT_LIST_HEAD(&host_driver->edev_list);
+
+       rc = refresh_exported_devices();
+       if (rc < 0)
+               return -1;
+
+       return 0;
+}
+
+int usbip_host_export_device(struct usbip_exported_device *edev, int sockfd)
+{
+       char attr_name[] = "usbip_sockfd";
+       char sockfd_attr_path[SYSFS_PATH_MAX];
+       char sockfd_buff[30];
+       int ret;
+
+       if (edev->status != SDEV_ST_AVAILABLE) {
+               dbg("device not available: %s", edev->udev.busid);
+               switch (edev->status) {
+               case SDEV_ST_ERROR:
+                       dbg("status SDEV_ST_ERROR");
+                       break;
+               case SDEV_ST_USED:
+                       dbg("status SDEV_ST_USED");
+                       break;
+               default:
+                       dbg("status unknown: 0x%x", edev->status);
+               }
+               return -1;
+       }
+
+       /* only the first interface is true */
+       snprintf(sockfd_attr_path, sizeof(sockfd_attr_path), "%s/%s",
+                edev->udev.path, attr_name);
+
+       snprintf(sockfd_buff, sizeof(sockfd_buff), "%d\n", sockfd);
+
+       ret = write_sysfs_attribute(sockfd_attr_path, sockfd_buff,
+                                   strlen(sockfd_buff));
+       if (ret < 0) {
+               err("write_sysfs_attribute failed: sockfd %s to %s",
+                   sockfd_buff, sockfd_attr_path);
+               return ret;
+       }
+
+       info("connect: %s", edev->udev.busid);
+
+       return ret;
+}
+
+struct usbip_exported_device *usbip_host_get_device(int num)
+{
+       struct list_head *i;
+       struct usbip_exported_device *edev;
+       int cnt = 0;
+
+       list_for_each(i, &host_driver->edev_list) {
+               edev = list_entry(i, struct usbip_exported_device, node);
+               if (num == cnt)
+                       return edev;
+               else
+                       cnt++;
+       }
+
+       return NULL;
+}
diff --git a/tools/usb/usbip/libsrc/usbip_host_driver.h b/tools/usb/usbip/libsrc/usbip_host_driver.h
new file mode 100644 (file)
index 0000000..2a31f85
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
+ *               2005-2007 Takahiro Hirofuchi
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __USBIP_HOST_DRIVER_H
+#define __USBIP_HOST_DRIVER_H
+
+#include <stdint.h>
+#include "usbip_common.h"
+#include "list.h"
+
+struct usbip_host_driver {
+       int ndevs;
+       /* list of exported device */
+       struct list_head edev_list;
+};
+
+struct usbip_exported_device {
+       struct udev_device *sudev;
+       int32_t status;
+       struct usbip_usb_device udev;
+       struct list_head node;
+       struct usbip_usb_interface uinf[];
+};
+
+extern struct usbip_host_driver *host_driver;
+
+int usbip_host_driver_open(void);
+void usbip_host_driver_close(void);
+
+int usbip_host_refresh_device_list(void);
+int usbip_host_export_device(struct usbip_exported_device *edev, int sockfd);
+struct usbip_exported_device *usbip_host_get_device(int num);
+
+#endif /* __USBIP_HOST_DRIVER_H */
diff --git a/tools/usb/usbip/libsrc/vhci_driver.c b/tools/usb/usbip/libsrc/vhci_driver.c
new file mode 100644 (file)
index 0000000..ad92047
--- /dev/null
@@ -0,0 +1,411 @@
+/*
+ * Copyright (C) 2005-2007 Takahiro Hirofuchi
+ */
+
+#include "usbip_common.h"
+#include "vhci_driver.h"
+#include <limits.h>
+#include <netdb.h>
+#include <libudev.h>
+#include "sysfs_utils.h"
+
+#undef  PROGNAME
+#define PROGNAME "libusbip"
+
+struct usbip_vhci_driver *vhci_driver;
+struct udev *udev_context;
+
+static struct usbip_imported_device *
+imported_device_init(struct usbip_imported_device *idev, char *busid)
+{
+       struct udev_device *sudev;
+
+       sudev = udev_device_new_from_subsystem_sysname(udev_context,
+                                                      "usb", busid);
+       if (!sudev) {
+               dbg("udev_device_new_from_subsystem_sysname failed: %s", busid);
+               goto err;
+       }
+       read_usb_device(sudev, &idev->udev);
+       udev_device_unref(sudev);
+
+       return idev;
+
+err:
+       return NULL;
+}
+
+
+
+static int parse_status(const char *value)
+{
+       int ret = 0;
+       char *c;
+
+
+       for (int i = 0; i < vhci_driver->nports; i++)
+               memset(&vhci_driver->idev[i], 0, sizeof(vhci_driver->idev[i]));
+
+
+       /* skip a header line */
+       c = strchr(value, '\n');
+       if (!c)
+               return -1;
+       c++;
+
+       while (*c != '\0') {
+               int port, status, speed, devid;
+               unsigned long socket;
+               char lbusid[SYSFS_BUS_ID_SIZE];
+
+               ret = sscanf(c, "%d %d %d %x %lx %31s\n",
+                               &port, &status, &speed,
+                               &devid, &socket, lbusid);
+
+               if (ret < 5) {
+                       dbg("sscanf failed: %d", ret);
+                       BUG();
+               }
+
+               dbg("port %d status %d speed %d devid %x",
+                               port, status, speed, devid);
+               dbg("socket %lx lbusid %s", socket, lbusid);
+
+
+               /* if a device is connected, look at it */
+               {
+                       struct usbip_imported_device *idev = &vhci_driver->idev[port];
+
+                       idev->port      = port;
+                       idev->status    = status;
+
+                       idev->devid     = devid;
+
+                       idev->busnum    = (devid >> 16);
+                       idev->devnum    = (devid & 0x0000ffff);
+
+                       if (idev->status != VDEV_ST_NULL
+                           && idev->status != VDEV_ST_NOTASSIGNED) {
+                               idev = imported_device_init(idev, lbusid);
+                               if (!idev) {
+                                       dbg("imported_device_init failed");
+                                       return -1;
+                               }
+                       }
+               }
+
+
+               /* go to the next line */
+               c = strchr(c, '\n');
+               if (!c)
+                       break;
+               c++;
+       }
+
+       dbg("exit");
+
+       return 0;
+}
+
+static int refresh_imported_device_list(void)
+{
+       const char *attr_status;
+
+       attr_status = udev_device_get_sysattr_value(vhci_driver->hc_device,
+                                              "status");
+       if (!attr_status) {
+               err("udev_device_get_sysattr_value failed");
+               return -1;
+       }
+
+       return parse_status(attr_status);
+}
+
+static int get_nports(void)
+{
+       char *c;
+       int nports = 0;
+       const char *attr_status;
+
+       attr_status = udev_device_get_sysattr_value(vhci_driver->hc_device,
+                                              "status");
+       if (!attr_status) {
+               err("udev_device_get_sysattr_value failed");
+               return -1;
+       }
+
+       /* skip a header line */
+       c = strchr(attr_status, '\n');
+       if (!c)
+               return 0;
+       c++;
+
+       while (*c != '\0') {
+               /* go to the next line */
+               c = strchr(c, '\n');
+               if (!c)
+                       return nports;
+               c++;
+               nports += 1;
+       }
+
+       return nports;
+}
+
+/*
+ * Read the given port's record.
+ *
+ * To avoid buffer overflow we will read the entire line and
+ * validate each part's size. The initial buffer is padded by 4 to
+ * accommodate the 2 spaces, 1 newline and an additional character
+ * which is needed to properly validate the 3rd part without it being
+ * truncated to an acceptable length.
+ */
+static int read_record(int rhport, char *host, unsigned long host_len,
+               char *port, unsigned long port_len, char *busid)
+{
+       int part;
+       FILE *file;
+       char path[PATH_MAX+1];
+       char *buffer, *start, *end;
+       char delim[] = {' ', ' ', '\n'};
+       int max_len[] = {(int)host_len, (int)port_len, SYSFS_BUS_ID_SIZE};
+       size_t buffer_len = host_len + port_len + SYSFS_BUS_ID_SIZE + 4;
+
+       buffer = malloc(buffer_len);
+       if (!buffer)
+               return -1;
+
+       snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport);
+
+       file = fopen(path, "r");
+       if (!file) {
+               err("fopen");
+               free(buffer);
+               return -1;
+       }
+
+       if (fgets(buffer, buffer_len, file) == NULL) {
+               err("fgets");
+               free(buffer);
+               fclose(file);
+               return -1;
+       }
+       fclose(file);
+
+       /* validate the length of each of the 3 parts */
+       start = buffer;
+       for (part = 0; part < 3; part++) {
+               end = strchr(start, delim[part]);
+               if (end == NULL || (end - start) > max_len[part]) {
+                       free(buffer);
+                       return -1;
+               }
+               start = end + 1;
+       }
+
+       if (sscanf(buffer, "%s %s %s\n", host, port, busid) != 3) {
+               err("sscanf");
+               free(buffer);
+               return -1;
+       }
+
+       free(buffer);
+
+       return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+int usbip_vhci_driver_open(void)
+{
+       udev_context = udev_new();
+       if (!udev_context) {
+               err("udev_new failed");
+               return -1;
+       }
+
+       vhci_driver = calloc(1, sizeof(struct usbip_vhci_driver));
+
+       /* will be freed in usbip_driver_close() */
+       vhci_driver->hc_device =
+               udev_device_new_from_subsystem_sysname(udev_context,
+                                                      USBIP_VHCI_BUS_TYPE,
+                                                      USBIP_VHCI_DRV_NAME);
+       if (!vhci_driver->hc_device) {
+               err("udev_device_new_from_subsystem_sysname failed");
+               goto err;
+       }
+
+       vhci_driver->nports = get_nports();
+
+       dbg("available ports: %d", vhci_driver->nports);
+
+       if (refresh_imported_device_list())
+               goto err;
+
+       return 0;
+
+err:
+       udev_device_unref(vhci_driver->hc_device);
+
+       if (vhci_driver)
+               free(vhci_driver);
+
+       vhci_driver = NULL;
+
+       udev_unref(udev_context);
+
+       return -1;
+}
+
+
+void usbip_vhci_driver_close(void)
+{
+       if (!vhci_driver)
+               return;
+
+       udev_device_unref(vhci_driver->hc_device);
+
+       free(vhci_driver);
+
+       vhci_driver = NULL;
+
+       udev_unref(udev_context);
+}
+
+
+int usbip_vhci_refresh_device_list(void)
+{
+
+       if (refresh_imported_device_list())
+               goto err;
+
+       return 0;
+err:
+       dbg("failed to refresh device list");
+       return -1;
+}
+
+
+int usbip_vhci_get_free_port(void)
+{
+       for (int i = 0; i < vhci_driver->nports; i++) {
+               if (vhci_driver->idev[i].status == VDEV_ST_NULL)
+                       return i;
+       }
+
+       return -1;
+}
+
+int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid,
+               uint32_t speed) {
+       char buff[200]; /* what size should be ? */
+       char attach_attr_path[SYSFS_PATH_MAX];
+       char attr_attach[] = "attach";
+       const char *path;
+       int ret;
+
+       snprintf(buff, sizeof(buff), "%u %d %u %u",
+                       port, sockfd, devid, speed);
+       dbg("writing: %s", buff);
+
+       path = udev_device_get_syspath(vhci_driver->hc_device);
+       snprintf(attach_attr_path, sizeof(attach_attr_path), "%s/%s",
+                path, attr_attach);
+       dbg("attach attribute path: %s", attach_attr_path);
+
+       ret = write_sysfs_attribute(attach_attr_path, buff, strlen(buff));
+       if (ret < 0) {
+               dbg("write_sysfs_attribute failed");
+               return -1;
+       }
+
+       dbg("attached port: %d", port);
+
+       return 0;
+}
+
+static unsigned long get_devid(uint8_t busnum, uint8_t devnum)
+{
+       return (busnum << 16) | devnum;
+}
+
+/* will be removed */
+int usbip_vhci_attach_device(uint8_t port, int sockfd, uint8_t busnum,
+               uint8_t devnum, uint32_t speed)
+{
+       int devid = get_devid(busnum, devnum);
+
+       return usbip_vhci_attach_device2(port, sockfd, devid, speed);
+}
+
+int usbip_vhci_detach_device(uint8_t port)
+{
+       char detach_attr_path[SYSFS_PATH_MAX];
+       char attr_detach[] = "detach";
+       char buff[200]; /* what size should be ? */
+       const char *path;
+       int ret;
+
+       snprintf(buff, sizeof(buff), "%u", port);
+       dbg("writing: %s", buff);
+
+       path = udev_device_get_syspath(vhci_driver->hc_device);
+       snprintf(detach_attr_path, sizeof(detach_attr_path), "%s/%s",
+                path, attr_detach);
+       dbg("detach attribute path: %s", detach_attr_path);
+
+       ret = write_sysfs_attribute(detach_attr_path, buff, strlen(buff));
+       if (ret < 0) {
+               dbg("write_sysfs_attribute failed");
+               return -1;
+       }
+
+       dbg("detached port: %d", port);
+
+       return 0;
+}
+
+int usbip_vhci_imported_device_dump(struct usbip_imported_device *idev)
+{
+       char product_name[100];
+       char host[NI_MAXHOST] = "unknown host";
+       char serv[NI_MAXSERV] = "unknown port";
+       char remote_busid[SYSFS_BUS_ID_SIZE];
+       int ret;
+       int read_record_error = 0;
+
+       if (idev->status == VDEV_ST_NULL || idev->status == VDEV_ST_NOTASSIGNED)
+               return 0;
+
+       ret = read_record(idev->port, host, sizeof(host), serv, sizeof(serv),
+                         remote_busid);
+       if (ret) {
+               err("read_record");
+               read_record_error = 1;
+       }
+
+       printf("Port %02d: <%s> at %s\n", idev->port,
+              usbip_status_string(idev->status),
+              usbip_speed_string(idev->udev.speed));
+
+       usbip_names_get_product(product_name, sizeof(product_name),
+                               idev->udev.idVendor, idev->udev.idProduct);
+
+       printf("       %s\n",  product_name);
+
+       if (!read_record_error) {
+               printf("%10s -> usbip://%s:%s/%s\n", idev->udev.busid,
+                      host, serv, remote_busid);
+               printf("%10s -> remote bus/dev %03d/%03d\n", " ",
+                      idev->busnum, idev->devnum);
+       } else {
+               printf("%10s -> unknown host, remote port and remote busid\n",
+                      idev->udev.busid);
+               printf("%10s -> remote bus/dev %03d/%03d\n", " ",
+                      idev->busnum, idev->devnum);
+       }
+
+       return 0;
+}
diff --git a/tools/usb/usbip/libsrc/vhci_driver.h b/tools/usb/usbip/libsrc/vhci_driver.h
new file mode 100644 (file)
index 0000000..fa2316c
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2005-2007 Takahiro Hirofuchi
+ */
+
+#ifndef __VHCI_DRIVER_H
+#define __VHCI_DRIVER_H
+
+#include <libudev.h>
+#include <stdint.h>
+
+#include "usbip_common.h"
+
+#define USBIP_VHCI_BUS_TYPE "platform"
+#define MAXNPORT 128
+
+struct usbip_imported_device {
+       uint8_t port;
+       uint32_t status;
+
+       uint32_t devid;
+
+       uint8_t busnum;
+       uint8_t devnum;
+
+       /* usbip_class_device list */
+       struct usbip_usb_device udev;
+};
+
+struct usbip_vhci_driver {
+
+       /* /sys/devices/platform/vhci_hcd */
+       struct udev_device *hc_device;
+
+       int nports;
+       struct usbip_imported_device idev[MAXNPORT];
+};
+
+
+extern struct usbip_vhci_driver *vhci_driver;
+
+int usbip_vhci_driver_open(void);
+void usbip_vhci_driver_close(void);
+
+int  usbip_vhci_refresh_device_list(void);
+
+
+int usbip_vhci_get_free_port(void);
+int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid,
+               uint32_t speed);
+
+/* will be removed */
+int usbip_vhci_attach_device(uint8_t port, int sockfd, uint8_t busnum,
+               uint8_t devnum, uint32_t speed);
+
+int usbip_vhci_detach_device(uint8_t port);
+
+int usbip_vhci_imported_device_dump(struct usbip_imported_device *idev);
+
+#endif /* __VHCI_DRIVER_H */
diff --git a/tools/usb/usbip/src/Makefile.am b/tools/usb/usbip/src/Makefile.am
new file mode 100644 (file)
index 0000000..e81a4eb
--- /dev/null
@@ -0,0 +1,11 @@
+AM_CPPFLAGS = -I$(top_srcdir)/libsrc -DUSBIDS_FILE='"@USBIDS_DIR@/usb.ids"'
+AM_CFLAGS   = @EXTRA_CFLAGS@
+LDADD       = $(top_builddir)/libsrc/libusbip.la
+
+sbin_PROGRAMS := usbip usbipd
+
+usbip_SOURCES := usbip.h utils.h usbip.c utils.c usbip_network.c \
+                usbip_attach.c usbip_detach.c usbip_list.c \
+                usbip_bind.c usbip_unbind.c usbip_port.c
+
+usbipd_SOURCES := usbip_network.h usbipd.c usbip_network.c
diff --git a/tools/usb/usbip/src/usbip.c b/tools/usb/usbip/src/usbip.c
new file mode 100644 (file)
index 0000000..d7599d9
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * command structure borrowed from udev
+ * (git://git.kernel.org/pub/scm/linux/hotplug/udev.git)
+ *
+ * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
+ *               2005-2007 Takahiro Hirofuchi
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <getopt.h>
+#include <syslog.h>
+
+#include "usbip_common.h"
+#include "usbip_network.h"
+#include "usbip.h"
+
+static int usbip_help(int argc, char *argv[]);
+static int usbip_version(int argc, char *argv[]);
+
+static const char usbip_version_string[] = PACKAGE_STRING;
+
+static const char usbip_usage_string[] =
+       "usbip [--debug] [--log] [--tcp-port PORT] [version]\n"
+       "             [help] <command> <args>\n";
+
+static void usbip_usage(void)
+{
+       printf("usage: %s", usbip_usage_string);
+}
+
+struct command {
+       const char *name;
+       int (*fn)(int argc, char *argv[]);
+       const char *help;
+       void (*usage)(void);
+};
+
+static const struct command cmds[] = {
+       {
+               .name  = "help",
+               .fn    = usbip_help,
+               .help  = NULL,
+               .usage = NULL
+       },
+       {
+               .name  = "version",
+               .fn    = usbip_version,
+               .help  = NULL,
+               .usage = NULL
+       },
+       {
+               .name  = "attach",
+               .fn    = usbip_attach,
+               .help  = "Attach a remote USB device",
+               .usage = usbip_attach_usage
+       },
+       {
+               .name  = "detach",
+               .fn    = usbip_detach,
+               .help  = "Detach a remote USB device",
+               .usage = usbip_detach_usage
+       },
+       {
+               .name  = "list",
+               .fn    = usbip_list,
+               .help  = "List exportable or local USB devices",
+               .usage = usbip_list_usage
+       },
+       {
+               .name  = "bind",
+               .fn    = usbip_bind,
+               .help  = "Bind device to " USBIP_HOST_DRV_NAME ".ko",
+               .usage = usbip_bind_usage
+       },
+       {
+               .name  = "unbind",
+               .fn    = usbip_unbind,
+               .help  = "Unbind device from " USBIP_HOST_DRV_NAME ".ko",
+               .usage = usbip_unbind_usage
+       },
+       {
+               .name  = "port",
+               .fn    = usbip_port_show,
+               .help  = "Show imported USB devices",
+               .usage = NULL
+       },
+       { NULL, NULL, NULL, NULL }
+};
+
+static int usbip_help(int argc, char *argv[])
+{
+       const struct command *cmd;
+       int i;
+       int ret = 0;
+
+       if (argc > 1 && argv++) {
+               for (i = 0; cmds[i].name != NULL; i++)
+                       if (!strcmp(cmds[i].name, argv[0]) && cmds[i].usage) {
+                               cmds[i].usage();
+                               goto done;
+                       }
+               ret = -1;
+       }
+
+       usbip_usage();
+       printf("\n");
+       for (cmd = cmds; cmd->name != NULL; cmd++)
+               if (cmd->help != NULL)
+                       printf("  %-10s %s\n", cmd->name, cmd->help);
+       printf("\n");
+done:
+       return ret;
+}
+
+static int usbip_version(int argc, char *argv[])
+{
+       (void) argc;
+       (void) argv;
+
+       printf(PROGNAME " (%s)\n", usbip_version_string);
+       return 0;
+}
+
+static int run_command(const struct command *cmd, int argc, char *argv[])
+{
+       dbg("running command: `%s'", cmd->name);
+       return cmd->fn(argc, argv);
+}
+
+int main(int argc, char *argv[])
+{
+       static const struct option opts[] = {
+               { "debug",    no_argument,       NULL, 'd' },
+               { "log",      no_argument,       NULL, 'l' },
+               { "tcp-port", required_argument, NULL, 't' },
+               { NULL,       0,                 NULL,  0  }
+       };
+
+       char *cmd;
+       int opt;
+       int i, rc = -1;
+
+       usbip_use_stderr = 1;
+       opterr = 0;
+       for (;;) {
+               opt = getopt_long(argc, argv, "+dlt:", opts, NULL);
+
+               if (opt == -1)
+                       break;
+
+               switch (opt) {
+               case 'd':
+                       usbip_use_debug = 1;
+                       break;
+               case 'l':
+                       usbip_use_syslog = 1;
+                       openlog("", LOG_PID, LOG_USER);
+                       break;
+               case 't':
+                       usbip_setup_port_number(optarg);
+                       break;
+               case '?':
+                       printf("usbip: invalid option\n");
+               default:
+                       usbip_usage();
+                       goto out;
+               }
+       }
+
+       cmd = argv[optind];
+       if (cmd) {
+               for (i = 0; cmds[i].name != NULL; i++)
+                       if (!strcmp(cmds[i].name, cmd)) {
+                               argc -= optind;
+                               argv += optind;
+                               optind = 0;
+                               rc = run_command(&cmds[i], argc, argv);
+                               goto out;
+                       }
+       }
+
+       /* invalid command */
+       usbip_help(0, NULL);
+out:
+       return (rc > -1 ? EXIT_SUCCESS : EXIT_FAILURE);
+}
diff --git a/tools/usb/usbip/src/usbip.h b/tools/usb/usbip/src/usbip.h
new file mode 100644 (file)
index 0000000..84fe66a
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
+ *               2005-2007 Takahiro Hirofuchi
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __USBIP_H
+#define __USBIP_H
+
+#ifdef HAVE_CONFIG_H
+#include "../config.h"
+#endif
+
+/* usbip commands */
+int usbip_attach(int argc, char *argv[]);
+int usbip_detach(int argc, char *argv[]);
+int usbip_list(int argc, char *argv[]);
+int usbip_bind(int argc, char *argv[]);
+int usbip_unbind(int argc, char *argv[]);
+int usbip_port_show(int argc, char *argv[]);
+
+void usbip_attach_usage(void);
+void usbip_detach_usage(void);
+void usbip_list_usage(void);
+void usbip_bind_usage(void);
+void usbip_unbind_usage(void);
+
+#endif /* __USBIP_H */
diff --git a/tools/usb/usbip/src/usbip_attach.c b/tools/usb/usbip/src/usbip_attach.c
new file mode 100644 (file)
index 0000000..d58a14d
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
+ *               2005-2007 Takahiro Hirofuchi
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/stat.h>
+
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <fcntl.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "vhci_driver.h"
+#include "usbip_common.h"
+#include "usbip_network.h"
+#include "usbip.h"
+
+static const char usbip_attach_usage_string[] =
+       "usbip attach <args>\n"
+       "    -r, --remote=<host>      The machine with exported USB devices\n"
+       "    -b, --busid=<busid>    Busid of the device on <host>\n";
+
+void usbip_attach_usage(void)
+{
+       printf("usage: %s", usbip_attach_usage_string);
+}
+
+#define MAX_BUFF 100
+static int record_connection(char *host, char *port, char *busid, int rhport)
+{
+       int fd;
+       char path[PATH_MAX+1];
+       char buff[MAX_BUFF+1];
+       int ret;
+
+       ret = mkdir(VHCI_STATE_PATH, 0700);
+       if (ret < 0) {
+               /* if VHCI_STATE_PATH exists, then it better be a directory */
+               if (errno == EEXIST) {
+                       struct stat s;
+
+                       ret = stat(VHCI_STATE_PATH, &s);
+                       if (ret < 0)
+                               return -1;
+                       if (!(s.st_mode & S_IFDIR))
+                               return -1;
+               } else
+                       return -1;
+       }
+
+       snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport);
+
+       fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU);
+       if (fd < 0)
+               return -1;
+
+       snprintf(buff, MAX_BUFF, "%s %s %s\n",
+                       host, port, busid);
+
+       ret = write(fd, buff, strlen(buff));
+       if (ret != (ssize_t) strlen(buff)) {
+               close(fd);
+               return -1;
+       }
+
+       close(fd);
+
+       return 0;
+}
+
+static int import_device(int sockfd, struct usbip_usb_device *udev)
+{
+       int rc;
+       int port;
+
+       rc = usbip_vhci_driver_open();
+       if (rc < 0) {
+               err("open vhci_driver");
+               return -1;
+       }
+
+       port = usbip_vhci_get_free_port();
+       if (port < 0) {
+               err("no free port");
+               usbip_vhci_driver_close();
+               return -1;
+       }
+
+       rc = usbip_vhci_attach_device(port, sockfd, udev->busnum,
+                                     udev->devnum, udev->speed);
+       if (rc < 0) {
+               err("import device");
+               usbip_vhci_driver_close();
+               return -1;
+       }
+
+       usbip_vhci_driver_close();
+
+       return port;
+}
+
+static int query_import_device(int sockfd, char *busid)
+{
+       int rc;
+       struct op_import_request request;
+       struct op_import_reply   reply;
+       uint16_t code = OP_REP_IMPORT;
+
+       memset(&request, 0, sizeof(request));
+       memset(&reply, 0, sizeof(reply));
+
+       /* send a request */
+       rc = usbip_net_send_op_common(sockfd, OP_REQ_IMPORT, 0);
+       if (rc < 0) {
+               err("send op_common");
+               return -1;
+       }
+
+       strncpy(request.busid, busid, SYSFS_BUS_ID_SIZE-1);
+
+       PACK_OP_IMPORT_REQUEST(0, &request);
+
+       rc = usbip_net_send(sockfd, (void *) &request, sizeof(request));
+       if (rc < 0) {
+               err("send op_import_request");
+               return -1;
+       }
+
+       /* receive a reply */
+       rc = usbip_net_recv_op_common(sockfd, &code);
+       if (rc < 0) {
+               err("recv op_common");
+               return -1;
+       }
+
+       rc = usbip_net_recv(sockfd, (void *) &reply, sizeof(reply));
+       if (rc < 0) {
+               err("recv op_import_reply");
+               return -1;
+       }
+
+       PACK_OP_IMPORT_REPLY(0, &reply);
+
+       /* check the reply */
+       if (strncmp(reply.udev.busid, busid, SYSFS_BUS_ID_SIZE)) {
+               err("recv different busid %s", reply.udev.busid);
+               return -1;
+       }
+
+       /* import a device */
+       return import_device(sockfd, &reply.udev);
+}
+
+static int attach_device(char *host, char *busid)
+{
+       int sockfd;
+       int rc;
+       int rhport;
+
+       sockfd = usbip_net_tcp_connect(host, usbip_port_string);
+       if (sockfd < 0) {
+               err("tcp connect");
+               return -1;
+       }
+
+       rhport = query_import_device(sockfd, busid);
+       if (rhport < 0) {
+               err("query");
+               return -1;
+       }
+
+       close(sockfd);
+
+       rc = record_connection(host, usbip_port_string, busid, rhport);
+       if (rc < 0) {
+               err("record connection");
+               return -1;
+       }
+
+       return 0;
+}
+
+int usbip_attach(int argc, char *argv[])
+{
+       static const struct option opts[] = {
+               { "remote", required_argument, NULL, 'r' },
+               { "busid",  required_argument, NULL, 'b' },
+               { NULL, 0,  NULL, 0 }
+       };
+       char *host = NULL;
+       char *busid = NULL;
+       int opt;
+       int ret = -1;
+
+       for (;;) {
+               opt = getopt_long(argc, argv, "r:b:", opts, NULL);
+
+               if (opt == -1)
+                       break;
+
+               switch (opt) {
+               case 'r':
+                       host = optarg;
+                       break;
+               case 'b':
+                       busid = optarg;
+                       break;
+               default:
+                       goto err_out;
+               }
+       }
+
+       if (!host || !busid)
+               goto err_out;
+
+       ret = attach_device(host, busid);
+       goto out;
+
+err_out:
+       usbip_attach_usage();
+out:
+       return ret;
+}
diff --git a/tools/usb/usbip/src/usbip_bind.c b/tools/usb/usbip/src/usbip_bind.c
new file mode 100644 (file)
index 0000000..fa46141
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
+ *               2005-2007 Takahiro Hirofuchi
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libudev.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <getopt.h>
+
+#include "usbip_common.h"
+#include "utils.h"
+#include "usbip.h"
+#include "sysfs_utils.h"
+
+enum unbind_status {
+       UNBIND_ST_OK,
+       UNBIND_ST_USBIP_HOST,
+       UNBIND_ST_FAILED
+};
+
+static const char usbip_bind_usage_string[] =
+       "usbip bind <args>\n"
+       "    -b, --busid=<busid>    Bind " USBIP_HOST_DRV_NAME ".ko to device "
+       "on <busid>\n";
+
+void usbip_bind_usage(void)
+{
+       printf("usage: %s", usbip_bind_usage_string);
+}
+
+/* call at unbound state */
+static int bind_usbip(char *busid)
+{
+       char attr_name[] = "bind";
+       char bind_attr_path[SYSFS_PATH_MAX];
+       int rc = -1;
+
+       snprintf(bind_attr_path, sizeof(bind_attr_path), "%s/%s/%s/%s/%s/%s",
+                SYSFS_MNT_PATH, SYSFS_BUS_NAME, SYSFS_BUS_TYPE,
+                SYSFS_DRIVERS_NAME, USBIP_HOST_DRV_NAME, attr_name);
+
+       rc = write_sysfs_attribute(bind_attr_path, busid, strlen(busid));
+       if (rc < 0) {
+               err("error binding device %s to driver: %s", busid,
+                   strerror(errno));
+               return -1;
+       }
+
+       return 0;
+}
+
+/* buggy driver may cause dead lock */
+static int unbind_other(char *busid)
+{
+       enum unbind_status status = UNBIND_ST_OK;
+
+       char attr_name[] = "unbind";
+       char unbind_attr_path[SYSFS_PATH_MAX];
+       int rc = -1;
+
+       struct udev *udev;
+       struct udev_device *dev;
+       const char *driver;
+       const char *bDevClass;
+
+       /* Create libudev context. */
+       udev = udev_new();
+
+       /* Get the device. */
+       dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid);
+       if (!dev) {
+               dbg("unable to find device with bus ID %s", busid);
+               goto err_close_busid_dev;
+       }
+
+       /* Check what kind of device it is. */
+       bDevClass  = udev_device_get_sysattr_value(dev, "bDeviceClass");
+       if (!bDevClass) {
+               dbg("unable to get bDevClass device attribute");
+               goto err_close_busid_dev;
+       }
+
+       if (!strncmp(bDevClass, "09", strlen(bDevClass))) {
+               dbg("skip unbinding of hub");
+               goto err_close_busid_dev;
+       }
+
+       /* Get the device driver. */
+       driver = udev_device_get_driver(dev);
+       if (!driver) {
+               /* No driver bound to this device. */
+               goto out;
+       }
+
+       if (!strncmp(USBIP_HOST_DRV_NAME, driver,
+                               strlen(USBIP_HOST_DRV_NAME))) {
+               /* Already bound to usbip-host. */
+               status = UNBIND_ST_USBIP_HOST;
+               goto out;
+       }
+
+       /* Unbind device from driver. */
+       snprintf(unbind_attr_path, sizeof(unbind_attr_path), "%s/%s/%s/%s/%s/%s",
+                SYSFS_MNT_PATH, SYSFS_BUS_NAME, SYSFS_BUS_TYPE,
+                SYSFS_DRIVERS_NAME, driver, attr_name);
+
+       rc = write_sysfs_attribute(unbind_attr_path, busid, strlen(busid));
+       if (rc < 0) {
+               err("error unbinding device %s from driver", busid);
+               goto err_close_busid_dev;
+       }
+
+       goto out;
+
+err_close_busid_dev:
+       status = UNBIND_ST_FAILED;
+out:
+       udev_device_unref(dev);
+       udev_unref(udev);
+
+       return status;
+}
+
+static int bind_device(char *busid)
+{
+       int rc;
+       struct udev *udev;
+       struct udev_device *dev;
+
+       /* Check whether the device with this bus ID exists. */
+       udev = udev_new();
+       dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid);
+       if (!dev) {
+               err("device with the specified bus ID does not exist");
+               return -1;
+       }
+       udev_unref(udev);
+
+       rc = unbind_other(busid);
+       if (rc == UNBIND_ST_FAILED) {
+               err("could not unbind driver from device on busid %s", busid);
+               return -1;
+       } else if (rc == UNBIND_ST_USBIP_HOST) {
+               err("device on busid %s is already bound to %s", busid,
+                   USBIP_HOST_DRV_NAME);
+               return -1;
+       }
+
+       rc = modify_match_busid(busid, 1);
+       if (rc < 0) {
+               err("unable to bind device on %s", busid);
+               return -1;
+       }
+
+       rc = bind_usbip(busid);
+       if (rc < 0) {
+               err("could not bind device to %s", USBIP_HOST_DRV_NAME);
+               modify_match_busid(busid, 0);
+               return -1;
+       }
+
+       info("bind device on busid %s: complete", busid);
+
+       return 0;
+}
+
+int usbip_bind(int argc, char *argv[])
+{
+       static const struct option opts[] = {
+               { "busid", required_argument, NULL, 'b' },
+               { NULL,    0,                 NULL,  0  }
+       };
+
+       int opt;
+       int ret = -1;
+
+       for (;;) {
+               opt = getopt_long(argc, argv, "b:", opts, NULL);
+
+               if (opt == -1)
+                       break;
+
+               switch (opt) {
+               case 'b':
+                       ret = bind_device(optarg);
+                       goto out;
+               default:
+                       goto err_out;
+               }
+       }
+
+err_out:
+       usbip_bind_usage();
+out:
+       return ret;
+}
diff --git a/tools/usb/usbip/src/usbip_detach.c b/tools/usb/usbip/src/usbip_detach.c
new file mode 100644 (file)
index 0000000..05c6d15
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
+ *               2005-2007 Takahiro Hirofuchi
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <ctype.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <getopt.h>
+#include <unistd.h>
+
+#include "vhci_driver.h"
+#include "usbip_common.h"
+#include "usbip_network.h"
+#include "usbip.h"
+
+static const char usbip_detach_usage_string[] =
+       "usbip detach <args>\n"
+       "    -p, --port=<port>    " USBIP_VHCI_DRV_NAME
+       " port the device is on\n";
+
+void usbip_detach_usage(void)
+{
+       printf("usage: %s", usbip_detach_usage_string);
+}
+
+static int detach_port(char *port)
+{
+       int ret;
+       uint8_t portnum;
+       char path[PATH_MAX+1];
+
+       for (unsigned int i = 0; i < strlen(port); i++)
+               if (!isdigit(port[i])) {
+                       err("invalid port %s", port);
+                       return -1;
+               }
+
+       /* check max port */
+
+       portnum = atoi(port);
+
+       /* remove the port state file */
+
+       snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", portnum);
+
+       remove(path);
+       rmdir(VHCI_STATE_PATH);
+
+       ret = usbip_vhci_driver_open();
+       if (ret < 0) {
+               err("open vhci_driver");
+               return -1;
+       }
+
+       ret = usbip_vhci_detach_device(portnum);
+       if (ret < 0)
+               return -1;
+
+       usbip_vhci_driver_close();
+
+       return ret;
+}
+
+int usbip_detach(int argc, char *argv[])
+{
+       static const struct option opts[] = {
+               { "port", required_argument, NULL, 'p' },
+               { NULL, 0, NULL, 0 }
+       };
+       int opt;
+       int ret = -1;
+
+       for (;;) {
+               opt = getopt_long(argc, argv, "p:", opts, NULL);
+
+               if (opt == -1)
+                       break;
+
+               switch (opt) {
+               case 'p':
+                       ret = detach_port(optarg);
+                       goto out;
+               default:
+                       goto err_out;
+               }
+       }
+
+err_out:
+       usbip_detach_usage();
+out:
+       return ret;
+}
diff --git a/tools/usb/usbip/src/usbip_list.c b/tools/usb/usbip/src/usbip_list.c
new file mode 100644 (file)
index 0000000..d5ce34a
--- /dev/null
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
+ *               2005-2007 Takahiro Hirofuchi
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <libudev.h>
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <getopt.h>
+#include <netdb.h>
+#include <unistd.h>
+
+#include "usbip_common.h"
+#include "usbip_network.h"
+#include "usbip.h"
+
+static const char usbip_list_usage_string[] =
+       "usbip list [-p|--parsable] <args>\n"
+       "    -p, --parsable         Parsable list format\n"
+       "    -r, --remote=<host>    List the exportable USB devices on <host>\n"
+       "    -l, --local            List the local USB devices\n";
+
+void usbip_list_usage(void)
+{
+       printf("usage: %s", usbip_list_usage_string);
+}
+
+static int get_exported_devices(char *host, int sockfd)
+{
+       char product_name[100];
+       char class_name[100];
+       struct op_devlist_reply reply;
+       uint16_t code = OP_REP_DEVLIST;
+       struct usbip_usb_device udev;
+       struct usbip_usb_interface uintf;
+       unsigned int i;
+       int rc, j;
+
+       rc = usbip_net_send_op_common(sockfd, OP_REQ_DEVLIST, 0);
+       if (rc < 0) {
+               dbg("usbip_net_send_op_common failed");
+               return -1;
+       }
+
+       rc = usbip_net_recv_op_common(sockfd, &code);
+       if (rc < 0) {
+               dbg("usbip_net_recv_op_common failed");
+               return -1;
+       }
+
+       memset(&reply, 0, sizeof(reply));
+       rc = usbip_net_recv(sockfd, &reply, sizeof(reply));
+       if (rc < 0) {
+               dbg("usbip_net_recv_op_devlist failed");
+               return -1;
+       }
+       PACK_OP_DEVLIST_REPLY(0, &reply);
+       dbg("exportable devices: %d\n", reply.ndev);
+
+       if (reply.ndev == 0) {
+               info("no exportable devices found on %s", host);
+               return 0;
+       }
+
+       printf("Exportable USB devices\n");
+       printf("======================\n");
+       printf(" - %s\n", host);
+
+       for (i = 0; i < reply.ndev; i++) {
+               memset(&udev, 0, sizeof(udev));
+               rc = usbip_net_recv(sockfd, &udev, sizeof(udev));
+               if (rc < 0) {
+                       dbg("usbip_net_recv failed: usbip_usb_device[%d]", i);
+                       return -1;
+               }
+               usbip_net_pack_usb_device(0, &udev);
+
+               usbip_names_get_product(product_name, sizeof(product_name),
+                                       udev.idVendor, udev.idProduct);
+               usbip_names_get_class(class_name, sizeof(class_name),
+                                     udev.bDeviceClass, udev.bDeviceSubClass,
+                                     udev.bDeviceProtocol);
+               printf("%11s: %s\n", udev.busid, product_name);
+               printf("%11s: %s\n", "", udev.path);
+               printf("%11s: %s\n", "", class_name);
+
+               for (j = 0; j < udev.bNumInterfaces; j++) {
+                       rc = usbip_net_recv(sockfd, &uintf, sizeof(uintf));
+                       if (rc < 0) {
+                               err("usbip_net_recv failed: usbip_usb_intf[%d]",
+                                               j);
+
+                               return -1;
+                       }
+                       usbip_net_pack_usb_interface(0, &uintf);
+
+                       usbip_names_get_class(class_name, sizeof(class_name),
+                                       uintf.bInterfaceClass,
+                                       uintf.bInterfaceSubClass,
+                                       uintf.bInterfaceProtocol);
+                       printf("%11s: %2d - %s\n", "", j, class_name);
+               }
+
+               printf("\n");
+       }
+
+       return 0;
+}
+
+static int list_exported_devices(char *host)
+{
+       int rc;
+       int sockfd;
+
+       sockfd = usbip_net_tcp_connect(host, usbip_port_string);
+       if (sockfd < 0) {
+               err("could not connect to %s:%s: %s", host,
+                   usbip_port_string, gai_strerror(sockfd));
+               return -1;
+       }
+       dbg("connected to %s:%s", host, usbip_port_string);
+
+       rc = get_exported_devices(host, sockfd);
+       if (rc < 0) {
+               err("failed to get device list from %s", host);
+               return -1;
+       }
+
+       close(sockfd);
+
+       return 0;
+}
+
+static void print_device(const char *busid, const char *vendor,
+                        const char *product, bool parsable)
+{
+       if (parsable)
+               printf("busid=%s#usbid=%.4s:%.4s#", busid, vendor, product);
+       else
+               printf(" - busid %s (%.4s:%.4s)\n", busid, vendor, product);
+}
+
+static void print_product_name(char *product_name, bool parsable)
+{
+       if (!parsable)
+               printf("   %s\n", product_name);
+}
+
+static int list_devices(bool parsable)
+{
+       struct udev *udev;
+       struct udev_enumerate *enumerate;
+       struct udev_list_entry *devices, *dev_list_entry;
+       struct udev_device *dev;
+       const char *path;
+       const char *idVendor;
+       const char *idProduct;
+       const char *bConfValue;
+       const char *bNumIntfs;
+       const char *busid;
+       char product_name[128];
+       int ret = -1;
+
+       /* Create libudev context. */
+       udev = udev_new();
+
+       /* Create libudev device enumeration. */
+       enumerate = udev_enumerate_new(udev);
+
+       /* Take only USB devices that are not hubs and do not have
+        * the bInterfaceNumber attribute, i.e. are not interfaces.
+        */
+       udev_enumerate_add_match_subsystem(enumerate, "usb");
+       udev_enumerate_add_nomatch_sysattr(enumerate, "bDeviceClass", "09");
+       udev_enumerate_add_nomatch_sysattr(enumerate, "bInterfaceNumber", NULL);
+       udev_enumerate_scan_devices(enumerate);
+
+       devices = udev_enumerate_get_list_entry(enumerate);
+
+       /* Show information about each device. */
+       udev_list_entry_foreach(dev_list_entry, devices) {
+               path = udev_list_entry_get_name(dev_list_entry);
+               dev = udev_device_new_from_syspath(udev, path);
+
+               /* Get device information. */
+               idVendor = udev_device_get_sysattr_value(dev, "idVendor");
+               idProduct = udev_device_get_sysattr_value(dev, "idProduct");
+               bConfValue = udev_device_get_sysattr_value(dev, "bConfigurationValue");
+               bNumIntfs = udev_device_get_sysattr_value(dev, "bNumInterfaces");
+               busid = udev_device_get_sysname(dev);
+               if (!idVendor || !idProduct || !bConfValue || !bNumIntfs) {
+                       err("problem getting device attributes: %s",
+                           strerror(errno));
+                       goto err_out;
+               }
+
+               /* Get product name. */
+               usbip_names_get_product(product_name, sizeof(product_name),
+                                       strtol(idVendor, NULL, 16),
+                                       strtol(idProduct, NULL, 16));
+
+               /* Print information. */
+               print_device(busid, idVendor, idProduct, parsable);
+               print_product_name(product_name, parsable);
+
+               printf("\n");
+
+               udev_device_unref(dev);
+       }
+
+       ret = 0;
+
+err_out:
+       udev_enumerate_unref(enumerate);
+       udev_unref(udev);
+
+       return ret;
+}
+
+int usbip_list(int argc, char *argv[])
+{
+       static const struct option opts[] = {
+               { "parsable", no_argument,       NULL, 'p' },
+               { "remote",   required_argument, NULL, 'r' },
+               { "local",    no_argument,       NULL, 'l' },
+               { NULL,       0,                 NULL,  0  }
+       };
+
+       bool parsable = false;
+       int opt;
+       int ret = -1;
+
+       if (usbip_names_init(USBIDS_FILE))
+               err("failed to open %s", USBIDS_FILE);
+
+       for (;;) {
+               opt = getopt_long(argc, argv, "pr:l", opts, NULL);
+
+               if (opt == -1)
+                       break;
+
+               switch (opt) {
+               case 'p':
+                       parsable = true;
+                       break;
+               case 'r':
+                       ret = list_exported_devices(optarg);
+                       goto out;
+               case 'l':
+                       ret = list_devices(parsable);
+                       goto out;
+               default:
+                       goto err_out;
+               }
+       }
+
+err_out:
+       usbip_list_usage();
+out:
+       usbip_names_free();
+
+       return ret;
+}
diff --git a/tools/usb/usbip/src/usbip_network.c b/tools/usb/usbip/src/usbip_network.c
new file mode 100644 (file)
index 0000000..b4c37e7
--- /dev/null
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
+ *               2005-2007 Takahiro Hirofuchi
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/socket.h>
+
+#include <string.h>
+
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <netinet/tcp.h>
+#include <unistd.h>
+
+#ifdef HAVE_LIBWRAP
+#include <tcpd.h>
+#endif
+
+#include "usbip_common.h"
+#include "usbip_network.h"
+
+int usbip_port = 3240;
+char *usbip_port_string = "3240";
+
+void usbip_setup_port_number(char *arg)
+{
+       dbg("parsing port arg '%s'", arg);
+       char *end;
+       unsigned long int port = strtoul(arg, &end, 10);
+
+       if (end == arg) {
+               err("port: could not parse '%s' as a decimal integer", arg);
+               return;
+       }
+
+       if (*end != '\0') {
+               err("port: garbage at end of '%s'", arg);
+               return;
+       }
+
+       if (port > UINT16_MAX) {
+               err("port: %s too high (max=%d)",
+                   arg, UINT16_MAX);
+               return;
+       }
+
+       usbip_port = port;
+       usbip_port_string = arg;
+       info("using port %d (\"%s\")", usbip_port, usbip_port_string);
+}
+
+void usbip_net_pack_uint32_t(int pack, uint32_t *num)
+{
+       uint32_t i;
+
+       if (pack)
+               i = htonl(*num);
+       else
+               i = ntohl(*num);
+
+       *num = i;
+}
+
+void usbip_net_pack_uint16_t(int pack, uint16_t *num)
+{
+       uint16_t i;
+
+       if (pack)
+               i = htons(*num);
+       else
+               i = ntohs(*num);
+
+       *num = i;
+}
+
+void usbip_net_pack_usb_device(int pack, struct usbip_usb_device *udev)
+{
+       usbip_net_pack_uint32_t(pack, &udev->busnum);
+       usbip_net_pack_uint32_t(pack, &udev->devnum);
+       usbip_net_pack_uint32_t(pack, &udev->speed);
+
+       usbip_net_pack_uint16_t(pack, &udev->idVendor);
+       usbip_net_pack_uint16_t(pack, &udev->idProduct);
+       usbip_net_pack_uint16_t(pack, &udev->bcdDevice);
+}
+
+void usbip_net_pack_usb_interface(int pack __attribute__((unused)),
+                                 struct usbip_usb_interface *udev
+                                 __attribute__((unused)))
+{
+       /* uint8_t members need nothing */
+}
+
+static ssize_t usbip_net_xmit(int sockfd, void *buff, size_t bufflen,
+                             int sending)
+{
+       ssize_t nbytes;
+       ssize_t total = 0;
+
+       if (!bufflen)
+               return 0;
+
+       do {
+               if (sending)
+                       nbytes = send(sockfd, buff, bufflen, 0);
+               else
+                       nbytes = recv(sockfd, buff, bufflen, MSG_WAITALL);
+
+               if (nbytes <= 0)
+                       return -1;
+
+               buff     = (void *)((intptr_t) buff + nbytes);
+               bufflen -= nbytes;
+               total   += nbytes;
+
+       } while (bufflen > 0);
+
+       return total;
+}
+
+ssize_t usbip_net_recv(int sockfd, void *buff, size_t bufflen)
+{
+       return usbip_net_xmit(sockfd, buff, bufflen, 0);
+}
+
+ssize_t usbip_net_send(int sockfd, void *buff, size_t bufflen)
+{
+       return usbip_net_xmit(sockfd, buff, bufflen, 1);
+}
+
+int usbip_net_send_op_common(int sockfd, uint32_t code, uint32_t status)
+{
+       struct op_common op_common;
+       int rc;
+
+       memset(&op_common, 0, sizeof(op_common));
+
+       op_common.version = USBIP_VERSION;
+       op_common.code    = code;
+       op_common.status  = status;
+
+       PACK_OP_COMMON(1, &op_common);
+
+       rc = usbip_net_send(sockfd, &op_common, sizeof(op_common));
+       if (rc < 0) {
+               dbg("usbip_net_send failed: %d", rc);
+               return -1;
+       }
+
+       return 0;
+}
+
+int usbip_net_recv_op_common(int sockfd, uint16_t *code)
+{
+       struct op_common op_common;
+       int rc;
+
+       memset(&op_common, 0, sizeof(op_common));
+
+       rc = usbip_net_recv(sockfd, &op_common, sizeof(op_common));
+       if (rc < 0) {
+               dbg("usbip_net_recv failed: %d", rc);
+               goto err;
+       }
+
+       PACK_OP_COMMON(0, &op_common);
+
+       if (op_common.version != USBIP_VERSION) {
+               dbg("version mismatch: %d %d", op_common.version,
+                   USBIP_VERSION);
+               goto err;
+       }
+
+       switch (*code) {
+       case OP_UNSPEC:
+               break;
+       default:
+               if (op_common.code != *code) {
+                       dbg("unexpected pdu %#0x for %#0x", op_common.code,
+                           *code);
+                       goto err;
+               }
+       }
+
+       if (op_common.status != ST_OK) {
+               dbg("request failed at peer: %d", op_common.status);
+               goto err;
+       }
+
+       *code = op_common.code;
+
+       return 0;
+err:
+       return -1;
+}
+
+int usbip_net_set_reuseaddr(int sockfd)
+{
+       const int val = 1;
+       int ret;
+
+       ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
+       if (ret < 0)
+               dbg("setsockopt: SO_REUSEADDR");
+
+       return ret;
+}
+
+int usbip_net_set_nodelay(int sockfd)
+{
+       const int val = 1;
+       int ret;
+
+       ret = setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
+       if (ret < 0)
+               dbg("setsockopt: TCP_NODELAY");
+
+       return ret;
+}
+
+int usbip_net_set_keepalive(int sockfd)
+{
+       const int val = 1;
+       int ret;
+
+       ret = setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val));
+       if (ret < 0)
+               dbg("setsockopt: SO_KEEPALIVE");
+
+       return ret;
+}
+
+int usbip_net_set_v6only(int sockfd)
+{
+       const int val = 1;
+       int ret;
+
+       ret = setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val));
+       if (ret < 0)
+               dbg("setsockopt: IPV6_V6ONLY");
+
+       return ret;
+}
+
+/*
+ * IPv6 Ready
+ */
+int usbip_net_tcp_connect(char *hostname, char *service)
+{
+       struct addrinfo hints, *res, *rp;
+       int sockfd;
+       int ret;
+
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_family = AF_UNSPEC;
+       hints.ai_socktype = SOCK_STREAM;
+
+       /* get all possible addresses */
+       ret = getaddrinfo(hostname, service, &hints, &res);
+       if (ret < 0) {
+               dbg("getaddrinfo: %s service %s: %s", hostname, service,
+                   gai_strerror(ret));
+               return ret;
+       }
+
+       /* try the addresses */
+       for (rp = res; rp; rp = rp->ai_next) {
+               sockfd = socket(rp->ai_family, rp->ai_socktype,
+                               rp->ai_protocol);
+               if (sockfd < 0)
+                       continue;
+
+               /* should set TCP_NODELAY for usbip */
+               usbip_net_set_nodelay(sockfd);
+               /* TODO: write code for heartbeat */
+               usbip_net_set_keepalive(sockfd);
+
+               if (connect(sockfd, rp->ai_addr, rp->ai_addrlen) == 0)
+                       break;
+
+               close(sockfd);
+       }
+
+       freeaddrinfo(res);
+
+       if (!rp)
+               return EAI_SYSTEM;
+
+       return sockfd;
+}
diff --git a/tools/usb/usbip/src/usbip_network.h b/tools/usb/usbip/src/usbip_network.h
new file mode 100644 (file)
index 0000000..c1e875c
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2005-2007 Takahiro Hirofuchi
+ */
+
+#ifndef __USBIP_NETWORK_H
+#define __USBIP_NETWORK_H
+
+#ifdef HAVE_CONFIG_H
+#include "../config.h"
+#endif
+
+#include <sys/types.h>
+
+#include <stdint.h>
+
+extern int usbip_port;
+extern char *usbip_port_string;
+void usbip_setup_port_number(char *arg);
+
+/* ---------------------------------------------------------------------- */
+/* Common header for all the kinds of PDUs. */
+struct op_common {
+       uint16_t version;
+
+#define OP_REQUEST     (0x80 << 8)
+#define OP_REPLY       (0x00 << 8)
+       uint16_t code;
+
+       /* add more error code */
+#define ST_OK  0x00
+#define ST_NA  0x01
+       uint32_t status; /* op_code status (for reply) */
+
+} __attribute__((packed));
+
+#define PACK_OP_COMMON(pack, op_common)  do {\
+       usbip_net_pack_uint16_t(pack, &(op_common)->version);\
+       usbip_net_pack_uint16_t(pack, &(op_common)->code);\
+       usbip_net_pack_uint32_t(pack, &(op_common)->status);\
+} while (0)
+
+/* ---------------------------------------------------------------------- */
+/* Dummy Code */
+#define OP_UNSPEC      0x00
+#define OP_REQ_UNSPEC  OP_UNSPEC
+#define OP_REP_UNSPEC  OP_UNSPEC
+
+/* ---------------------------------------------------------------------- */
+/* Retrieve USB device information. (still not used) */
+#define OP_DEVINFO     0x02
+#define OP_REQ_DEVINFO (OP_REQUEST | OP_DEVINFO)
+#define OP_REP_DEVINFO (OP_REPLY   | OP_DEVINFO)
+
+struct op_devinfo_request {
+       char busid[SYSFS_BUS_ID_SIZE];
+} __attribute__((packed));
+
+struct op_devinfo_reply {
+       struct usbip_usb_device udev;
+       struct usbip_usb_interface uinf[];
+} __attribute__((packed));
+
+/* ---------------------------------------------------------------------- */
+/* Import a remote USB device. */
+#define OP_IMPORT      0x03
+#define OP_REQ_IMPORT  (OP_REQUEST | OP_IMPORT)
+#define OP_REP_IMPORT   (OP_REPLY   | OP_IMPORT)
+
+struct op_import_request {
+       char busid[SYSFS_BUS_ID_SIZE];
+} __attribute__((packed));
+
+struct op_import_reply {
+       struct usbip_usb_device udev;
+//     struct usbip_usb_interface uinf[];
+} __attribute__((packed));
+
+#define PACK_OP_IMPORT_REQUEST(pack, request)  do {\
+} while (0)
+
+#define PACK_OP_IMPORT_REPLY(pack, reply)  do {\
+       usbip_net_pack_usb_device(pack, &(reply)->udev);\
+} while (0)
+
+/* ---------------------------------------------------------------------- */
+/* Export a USB device to a remote host. */
+#define OP_EXPORT      0x06
+#define OP_REQ_EXPORT  (OP_REQUEST | OP_EXPORT)
+#define OP_REP_EXPORT  (OP_REPLY   | OP_EXPORT)
+
+struct op_export_request {
+       struct usbip_usb_device udev;
+} __attribute__((packed));
+
+struct op_export_reply {
+       int returncode;
+} __attribute__((packed));
+
+
+#define PACK_OP_EXPORT_REQUEST(pack, request)  do {\
+       usbip_net_pack_usb_device(pack, &(request)->udev);\
+} while (0)
+
+#define PACK_OP_EXPORT_REPLY(pack, reply)  do {\
+} while (0)
+
+/* ---------------------------------------------------------------------- */
+/* un-Export a USB device from a remote host. */
+#define OP_UNEXPORT    0x07
+#define OP_REQ_UNEXPORT        (OP_REQUEST | OP_UNEXPORT)
+#define OP_REP_UNEXPORT        (OP_REPLY   | OP_UNEXPORT)
+
+struct op_unexport_request {
+       struct usbip_usb_device udev;
+} __attribute__((packed));
+
+struct op_unexport_reply {
+       int returncode;
+} __attribute__((packed));
+
+#define PACK_OP_UNEXPORT_REQUEST(pack, request)  do {\
+       usbip_net_pack_usb_device(pack, &(request)->udev);\
+} while (0)
+
+#define PACK_OP_UNEXPORT_REPLY(pack, reply)  do {\
+} while (0)
+
+/* ---------------------------------------------------------------------- */
+/* Negotiate IPSec encryption key. (still not used) */
+#define OP_CRYPKEY     0x04
+#define OP_REQ_CRYPKEY (OP_REQUEST | OP_CRYPKEY)
+#define OP_REP_CRYPKEY (OP_REPLY   | OP_CRYPKEY)
+
+struct op_crypkey_request {
+       /* 128bit key */
+       uint32_t key[4];
+} __attribute__((packed));
+
+struct op_crypkey_reply {
+       uint32_t __reserved;
+} __attribute__((packed));
+
+
+/* ---------------------------------------------------------------------- */
+/* Retrieve the list of exported USB devices. */
+#define OP_DEVLIST     0x05
+#define OP_REQ_DEVLIST (OP_REQUEST | OP_DEVLIST)
+#define OP_REP_DEVLIST (OP_REPLY   | OP_DEVLIST)
+
+struct op_devlist_request {
+} __attribute__((packed));
+
+struct op_devlist_reply {
+       uint32_t ndev;
+       /* followed by reply_extra[] */
+} __attribute__((packed));
+
+struct op_devlist_reply_extra {
+       struct usbip_usb_device    udev;
+       struct usbip_usb_interface uinf[];
+} __attribute__((packed));
+
+#define PACK_OP_DEVLIST_REQUEST(pack, request)  do {\
+} while (0)
+
+#define PACK_OP_DEVLIST_REPLY(pack, reply)  do {\
+       usbip_net_pack_uint32_t(pack, &(reply)->ndev);\
+} while (0)
+
+void usbip_net_pack_uint32_t(int pack, uint32_t *num);
+void usbip_net_pack_uint16_t(int pack, uint16_t *num);
+void usbip_net_pack_usb_device(int pack, struct usbip_usb_device *udev);
+void usbip_net_pack_usb_interface(int pack, struct usbip_usb_interface *uinf);
+
+ssize_t usbip_net_recv(int sockfd, void *buff, size_t bufflen);
+ssize_t usbip_net_send(int sockfd, void *buff, size_t bufflen);
+int usbip_net_send_op_common(int sockfd, uint32_t code, uint32_t status);
+int usbip_net_recv_op_common(int sockfd, uint16_t *code);
+int usbip_net_set_reuseaddr(int sockfd);
+int usbip_net_set_nodelay(int sockfd);
+int usbip_net_set_keepalive(int sockfd);
+int usbip_net_set_v6only(int sockfd);
+int usbip_net_tcp_connect(char *hostname, char *port);
+
+#endif /* __USBIP_NETWORK_H */
diff --git a/tools/usb/usbip/src/usbip_port.c b/tools/usb/usbip/src/usbip_port.c
new file mode 100644 (file)
index 0000000..a2e884f
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
+ *               2005-2007 Takahiro Hirofuchi
+ *
+ * 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.
+ */
+
+#include "vhci_driver.h"
+#include "usbip_common.h"
+
+static int list_imported_devices(void)
+{
+       int i;
+       struct usbip_imported_device *idev;
+       int ret;
+
+       ret = usbip_vhci_driver_open();
+       if (ret < 0) {
+               err("open vhci_driver");
+               return -1;
+       }
+
+       printf("Imported USB devices\n");
+       printf("====================\n");
+
+       for (i = 0; i < vhci_driver->nports; i++) {
+               idev = &vhci_driver->idev[i];
+
+               if (usbip_vhci_imported_device_dump(idev) < 0)
+                       ret = -1;
+       }
+
+       usbip_vhci_driver_close();
+
+       return ret;
+
+}
+
+int usbip_port_show(__attribute__((unused)) int argc,
+                   __attribute__((unused)) char *argv[])
+{
+       int ret;
+
+       ret = list_imported_devices();
+       if (ret < 0)
+               err("list imported devices");
+
+       return ret;
+}
diff --git a/tools/usb/usbip/src/usbip_unbind.c b/tools/usb/usbip/src/usbip_unbind.c
new file mode 100644 (file)
index 0000000..a4a496c
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
+ *               2005-2007 Takahiro Hirofuchi
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libudev.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <getopt.h>
+
+#include "usbip_common.h"
+#include "utils.h"
+#include "usbip.h"
+#include "sysfs_utils.h"
+
+static const char usbip_unbind_usage_string[] =
+       "usbip unbind <args>\n"
+       "    -b, --busid=<busid>    Unbind " USBIP_HOST_DRV_NAME ".ko from "
+       "device on <busid>\n";
+
+void usbip_unbind_usage(void)
+{
+       printf("usage: %s", usbip_unbind_usage_string);
+}
+
+static int unbind_device(char *busid)
+{
+       char bus_type[] = "usb";
+       int rc, ret = -1;
+
+       char unbind_attr_name[] = "unbind";
+       char unbind_attr_path[SYSFS_PATH_MAX];
+       char rebind_attr_name[] = "rebind";
+       char rebind_attr_path[SYSFS_PATH_MAX];
+
+       struct udev *udev;
+       struct udev_device *dev;
+       const char *driver;
+
+       /* Create libudev context. */
+       udev = udev_new();
+
+       /* Check whether the device with this bus ID exists. */
+       dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid);
+       if (!dev) {
+               err("device with the specified bus ID does not exist");
+               goto err_close_udev;
+       }
+
+       /* Check whether the device is using usbip-host driver. */
+       driver = udev_device_get_driver(dev);
+       if (!driver || strcmp(driver, "usbip-host")) {
+               err("device is not bound to usbip-host driver");
+               goto err_close_udev;
+       }
+
+       /* Unbind device from driver. */
+       snprintf(unbind_attr_path, sizeof(unbind_attr_path), "%s/%s/%s/%s/%s/%s",
+                SYSFS_MNT_PATH, SYSFS_BUS_NAME, bus_type, SYSFS_DRIVERS_NAME,
+                USBIP_HOST_DRV_NAME, unbind_attr_name);
+
+       rc = write_sysfs_attribute(unbind_attr_path, busid, strlen(busid));
+       if (rc < 0) {
+               err("error unbinding device %s from driver", busid);
+               goto err_close_udev;
+       }
+
+       /* Notify driver of unbind. */
+       rc = modify_match_busid(busid, 0);
+       if (rc < 0) {
+               err("unable to unbind device on %s", busid);
+               goto err_close_udev;
+       }
+
+       /* Trigger new probing. */
+       snprintf(rebind_attr_path, sizeof(unbind_attr_path), "%s/%s/%s/%s/%s/%s",
+                       SYSFS_MNT_PATH, SYSFS_BUS_NAME, bus_type, SYSFS_DRIVERS_NAME,
+                       USBIP_HOST_DRV_NAME, rebind_attr_name);
+
+       rc = write_sysfs_attribute(rebind_attr_path, busid, strlen(busid));
+       if (rc < 0) {
+               err("error rebinding");
+               goto err_close_udev;
+       }
+
+       ret = 0;
+       info("unbind device on busid %s: complete", busid);
+
+err_close_udev:
+       udev_device_unref(dev);
+       udev_unref(udev);
+
+       return ret;
+}
+
+int usbip_unbind(int argc, char *argv[])
+{
+       static const struct option opts[] = {
+               { "busid", required_argument, NULL, 'b' },
+               { NULL,    0,                 NULL,  0  }
+       };
+
+       int opt;
+       int ret = -1;
+
+       for (;;) {
+               opt = getopt_long(argc, argv, "b:", opts, NULL);
+
+               if (opt == -1)
+                       break;
+
+               switch (opt) {
+               case 'b':
+                       ret = unbind_device(optarg);
+                       goto out;
+               default:
+                       goto err_out;
+               }
+       }
+
+err_out:
+       usbip_unbind_usage();
+out:
+       return ret;
+}
diff --git a/tools/usb/usbip/src/usbipd.c b/tools/usb/usbip/src/usbipd.c
new file mode 100644 (file)
index 0000000..2f87f2d
--- /dev/null
@@ -0,0 +1,679 @@
+/*
+ * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
+ *               2005-2007 Takahiro Hirofuchi
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "../config.h"
+#endif
+
+#define _GNU_SOURCE
+#include <errno.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#ifdef HAVE_LIBWRAP
+#include <tcpd.h>
+#endif
+
+#include <getopt.h>
+#include <signal.h>
+#include <poll.h>
+
+#include "usbip_host_driver.h"
+#include "usbip_common.h"
+#include "usbip_network.h"
+#include "list.h"
+
+#undef  PROGNAME
+#define PROGNAME "usbipd"
+#define MAXSOCKFD 20
+
+#define MAIN_LOOP_TIMEOUT 10
+
+#define DEFAULT_PID_FILE "/var/run/" PROGNAME ".pid"
+
+static const char usbip_version_string[] = PACKAGE_STRING;
+
+static const char usbipd_help_string[] =
+       "usage: usbipd [options]\n"
+       "\n"
+       "       -4, --ipv4\n"
+       "               Bind to IPv4. Default is both.\n"
+       "\n"
+       "       -6, --ipv6\n"
+       "               Bind to IPv6. Default is both.\n"
+       "\n"
+       "       -D, --daemon\n"
+       "               Run as a daemon process.\n"
+       "\n"
+       "       -d, --debug\n"
+       "               Print debugging information.\n"
+       "\n"
+       "       -PFILE, --pid FILE\n"
+       "               Write process id to FILE.\n"
+       "               If no FILE specified, use " DEFAULT_PID_FILE "\n"
+       "\n"
+       "       -tPORT, --tcp-port PORT\n"
+       "               Listen on TCP/IP port PORT.\n"
+       "\n"
+       "       -h, --help\n"
+       "               Print this help.\n"
+       "\n"
+       "       -v, --version\n"
+       "               Show version.\n";
+
+static void usbipd_help(void)
+{
+       printf("%s\n", usbipd_help_string);
+}
+
+static int recv_request_import(int sockfd)
+{
+       struct op_import_request req;
+       struct op_common reply;
+       struct usbip_exported_device *edev;
+       struct usbip_usb_device pdu_udev;
+       struct list_head *i;
+       int found = 0;
+       int error = 0;
+       int rc;
+
+       memset(&req, 0, sizeof(req));
+       memset(&reply, 0, sizeof(reply));
+
+       rc = usbip_net_recv(sockfd, &req, sizeof(req));
+       if (rc < 0) {
+               dbg("usbip_net_recv failed: import request");
+               return -1;
+       }
+       PACK_OP_IMPORT_REQUEST(0, &req);
+
+       list_for_each(i, &host_driver->edev_list) {
+               edev = list_entry(i, struct usbip_exported_device, node);
+               if (!strncmp(req.busid, edev->udev.busid, SYSFS_BUS_ID_SIZE)) {
+                       info("found requested device: %s", req.busid);
+                       found = 1;
+                       break;
+               }
+       }
+
+       if (found) {
+               /* should set TCP_NODELAY for usbip */
+               usbip_net_set_nodelay(sockfd);
+
+               /* export device needs a TCP/IP socket descriptor */
+               rc = usbip_host_export_device(edev, sockfd);
+               if (rc < 0)
+                       error = 1;
+       } else {
+               info("requested device not found: %s", req.busid);
+               error = 1;
+       }
+
+       rc = usbip_net_send_op_common(sockfd, OP_REP_IMPORT,
+                                     (!error ? ST_OK : ST_NA));
+       if (rc < 0) {
+               dbg("usbip_net_send_op_common failed: %#0x", OP_REP_IMPORT);
+               return -1;
+       }
+
+       if (error) {
+               dbg("import request busid %s: failed", req.busid);
+               return -1;
+       }
+
+       memcpy(&pdu_udev, &edev->udev, sizeof(pdu_udev));
+       usbip_net_pack_usb_device(1, &pdu_udev);
+
+       rc = usbip_net_send(sockfd, &pdu_udev, sizeof(pdu_udev));
+       if (rc < 0) {
+               dbg("usbip_net_send failed: devinfo");
+               return -1;
+       }
+
+       dbg("import request busid %s: complete", req.busid);
+
+       return 0;
+}
+
+static int send_reply_devlist(int connfd)
+{
+       struct usbip_exported_device *edev;
+       struct usbip_usb_device pdu_udev;
+       struct usbip_usb_interface pdu_uinf;
+       struct op_devlist_reply reply;
+       struct list_head *j;
+       int rc, i;
+
+       reply.ndev = 0;
+       /* number of exported devices */
+       list_for_each(j, &host_driver->edev_list) {
+               reply.ndev += 1;
+       }
+       info("exportable devices: %d", reply.ndev);
+
+       rc = usbip_net_send_op_common(connfd, OP_REP_DEVLIST, ST_OK);
+       if (rc < 0) {
+               dbg("usbip_net_send_op_common failed: %#0x", OP_REP_DEVLIST);
+               return -1;
+       }
+       PACK_OP_DEVLIST_REPLY(1, &reply);
+
+       rc = usbip_net_send(connfd, &reply, sizeof(reply));
+       if (rc < 0) {
+               dbg("usbip_net_send failed: %#0x", OP_REP_DEVLIST);
+               return -1;
+       }
+
+       list_for_each(j, &host_driver->edev_list) {
+               edev = list_entry(j, struct usbip_exported_device, node);
+               dump_usb_device(&edev->udev);
+               memcpy(&pdu_udev, &edev->udev, sizeof(pdu_udev));
+               usbip_net_pack_usb_device(1, &pdu_udev);
+
+               rc = usbip_net_send(connfd, &pdu_udev, sizeof(pdu_udev));
+               if (rc < 0) {
+                       dbg("usbip_net_send failed: pdu_udev");
+                       return -1;
+               }
+
+               for (i = 0; i < edev->udev.bNumInterfaces; i++) {
+                       dump_usb_interface(&edev->uinf[i]);
+                       memcpy(&pdu_uinf, &edev->uinf[i], sizeof(pdu_uinf));
+                       usbip_net_pack_usb_interface(1, &pdu_uinf);
+
+                       rc = usbip_net_send(connfd, &pdu_uinf,
+                                       sizeof(pdu_uinf));
+                       if (rc < 0) {
+                               err("usbip_net_send failed: pdu_uinf");
+                               return -1;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int recv_request_devlist(int connfd)
+{
+       struct op_devlist_request req;
+       int rc;
+
+       memset(&req, 0, sizeof(req));
+
+       rc = usbip_net_recv(connfd, &req, sizeof(req));
+       if (rc < 0) {
+               dbg("usbip_net_recv failed: devlist request");
+               return -1;
+       }
+
+       rc = send_reply_devlist(connfd);
+       if (rc < 0) {
+               dbg("send_reply_devlist failed");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int recv_pdu(int connfd)
+{
+       uint16_t code = OP_UNSPEC;
+       int ret;
+
+       ret = usbip_net_recv_op_common(connfd, &code);
+       if (ret < 0) {
+               dbg("could not receive opcode: %#0x", code);
+               return -1;
+       }
+
+       ret = usbip_host_refresh_device_list();
+       if (ret < 0) {
+               dbg("could not refresh device list: %d", ret);
+               return -1;
+       }
+
+       info("received request: %#0x(%d)", code, connfd);
+       switch (code) {
+       case OP_REQ_DEVLIST:
+               ret = recv_request_devlist(connfd);
+               break;
+       case OP_REQ_IMPORT:
+               ret = recv_request_import(connfd);
+               break;
+       case OP_REQ_DEVINFO:
+       case OP_REQ_CRYPKEY:
+       default:
+               err("received an unknown opcode: %#0x", code);
+               ret = -1;
+       }
+
+       if (ret == 0)
+               info("request %#0x(%d): complete", code, connfd);
+       else
+               info("request %#0x(%d): failed", code, connfd);
+
+       return ret;
+}
+
+#ifdef HAVE_LIBWRAP
+static int tcpd_auth(int connfd)
+{
+       struct request_info request;
+       int rc;
+
+       request_init(&request, RQ_DAEMON, PROGNAME, RQ_FILE, connfd, 0);
+       fromhost(&request);
+       rc = hosts_access(&request);
+       if (rc == 0)
+               return -1;
+
+       return 0;
+}
+#endif
+
+static int do_accept(int listenfd)
+{
+       int connfd;
+       struct sockaddr_storage ss;
+       socklen_t len = sizeof(ss);
+       char host[NI_MAXHOST], port[NI_MAXSERV];
+       int rc;
+
+       memset(&ss, 0, sizeof(ss));
+
+       connfd = accept(listenfd, (struct sockaddr *)&ss, &len);
+       if (connfd < 0) {
+               err("failed to accept connection");
+               return -1;
+       }
+
+       rc = getnameinfo((struct sockaddr *)&ss, len, host, sizeof(host),
+                        port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV);
+       if (rc)
+               err("getnameinfo: %s", gai_strerror(rc));
+
+#ifdef HAVE_LIBWRAP
+       rc = tcpd_auth(connfd);
+       if (rc < 0) {
+               info("denied access from %s", host);
+               close(connfd);
+               return -1;
+       }
+#endif
+       info("connection from %s:%s", host, port);
+
+       return connfd;
+}
+
+int process_request(int listenfd)
+{
+       pid_t childpid;
+       int connfd;
+
+       connfd = do_accept(listenfd);
+       if (connfd < 0)
+               return -1;
+       childpid = fork();
+       if (childpid == 0) {
+               close(listenfd);
+               recv_pdu(connfd);
+               exit(0);
+       }
+       close(connfd);
+       return 0;
+}
+
+static void addrinfo_to_text(struct addrinfo *ai, char buf[],
+                            const size_t buf_size)
+{
+       char hbuf[NI_MAXHOST];
+       char sbuf[NI_MAXSERV];
+       int rc;
+
+       buf[0] = '\0';
+
+       rc = getnameinfo(ai->ai_addr, ai->ai_addrlen, hbuf, sizeof(hbuf),
+                        sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV);
+       if (rc)
+               err("getnameinfo: %s", gai_strerror(rc));
+
+       snprintf(buf, buf_size, "%s:%s", hbuf, sbuf);
+}
+
+static int listen_all_addrinfo(struct addrinfo *ai_head, int sockfdlist[],
+                            int maxsockfd)
+{
+       struct addrinfo *ai;
+       int ret, nsockfd = 0;
+       const size_t ai_buf_size = NI_MAXHOST + NI_MAXSERV + 2;
+       char ai_buf[ai_buf_size];
+
+       for (ai = ai_head; ai && nsockfd < maxsockfd; ai = ai->ai_next) {
+               int sock;
+
+               addrinfo_to_text(ai, ai_buf, ai_buf_size);
+               dbg("opening %s", ai_buf);
+               sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+               if (sock < 0) {
+                       err("socket: %s: %d (%s)",
+                           ai_buf, errno, strerror(errno));
+                       continue;
+               }
+
+               usbip_net_set_reuseaddr(sock);
+               usbip_net_set_nodelay(sock);
+               /* We use seperate sockets for IPv4 and IPv6
+                * (see do_standalone_mode()) */
+               usbip_net_set_v6only(sock);
+
+               if (sock >= FD_SETSIZE) {
+                       err("FD_SETSIZE: %s: sock=%d, max=%d",
+                           ai_buf, sock, FD_SETSIZE);
+                       close(sock);
+                       continue;
+               }
+
+               ret = bind(sock, ai->ai_addr, ai->ai_addrlen);
+               if (ret < 0) {
+                       err("bind: %s: %d (%s)",
+                           ai_buf, errno, strerror(errno));
+                       close(sock);
+                       continue;
+               }
+
+               ret = listen(sock, SOMAXCONN);
+               if (ret < 0) {
+                       err("listen: %s: %d (%s)",
+                           ai_buf, errno, strerror(errno));
+                       close(sock);
+                       continue;
+               }
+
+               info("listening on %s", ai_buf);
+               sockfdlist[nsockfd++] = sock;
+       }
+
+       return nsockfd;
+}
+
+static struct addrinfo *do_getaddrinfo(char *host, int ai_family)
+{
+       struct addrinfo hints, *ai_head;
+       int rc;
+
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_family   = ai_family;
+       hints.ai_socktype = SOCK_STREAM;
+       hints.ai_flags    = AI_PASSIVE;
+
+       rc = getaddrinfo(host, usbip_port_string, &hints, &ai_head);
+       if (rc) {
+               err("failed to get a network address %s: %s", usbip_port_string,
+                   gai_strerror(rc));
+               return NULL;
+       }
+
+       return ai_head;
+}
+
+static void signal_handler(int i)
+{
+       dbg("received '%s' signal", strsignal(i));
+}
+
+static void set_signal(void)
+{
+       struct sigaction act;
+
+       memset(&act, 0, sizeof(act));
+       act.sa_handler = signal_handler;
+       sigemptyset(&act.sa_mask);
+       sigaction(SIGTERM, &act, NULL);
+       sigaction(SIGINT, &act, NULL);
+       act.sa_handler = SIG_IGN;
+       sigaction(SIGCLD, &act, NULL);
+}
+
+static const char *pid_file;
+
+static void write_pid_file(void)
+{
+       if (pid_file) {
+               dbg("creating pid file %s", pid_file);
+               FILE *fp;
+
+               fp = fopen(pid_file, "w");
+               if (!fp) {
+                       err("pid_file: %s: %d (%s)",
+                           pid_file, errno, strerror(errno));
+                       return;
+               }
+               fprintf(fp, "%d\n", getpid());
+               fclose(fp);
+       }
+}
+
+static void remove_pid_file(void)
+{
+       if (pid_file) {
+               dbg("removing pid file %s", pid_file);
+               unlink(pid_file);
+       }
+}
+
+static int do_standalone_mode(int daemonize, int ipv4, int ipv6)
+{
+       struct addrinfo *ai_head;
+       int sockfdlist[MAXSOCKFD];
+       int nsockfd, family;
+       int i, terminate;
+       struct pollfd *fds;
+       struct timespec timeout;
+       sigset_t sigmask;
+
+       if (usbip_host_driver_open()) {
+               err("please load " USBIP_CORE_MOD_NAME ".ko and "
+                   USBIP_HOST_DRV_NAME ".ko!");
+               return -1;
+       }
+
+       if (daemonize) {
+               if (daemon(0, 0) < 0) {
+                       err("daemonizing failed: %s", strerror(errno));
+                       usbip_host_driver_close();
+                       return -1;
+               }
+               umask(0);
+               usbip_use_syslog = 1;
+       }
+       set_signal();
+       write_pid_file();
+
+       info("starting " PROGNAME " (%s)", usbip_version_string);
+
+       /*
+        * To suppress warnings on systems with bindv6only disabled
+        * (default), we use seperate sockets for IPv6 and IPv4 and set
+        * IPV6_V6ONLY on the IPv6 sockets.
+        */
+       if (ipv4 && ipv6)
+               family = AF_UNSPEC;
+       else if (ipv4)
+               family = AF_INET;
+       else
+               family = AF_INET6;
+
+       ai_head = do_getaddrinfo(NULL, family);
+       if (!ai_head) {
+               usbip_host_driver_close();
+               return -1;
+       }
+       nsockfd = listen_all_addrinfo(ai_head, sockfdlist,
+               sizeof(sockfdlist) / sizeof(*sockfdlist));
+       freeaddrinfo(ai_head);
+       if (nsockfd <= 0) {
+               err("failed to open a listening socket");
+               usbip_host_driver_close();
+               return -1;
+       }
+
+       dbg("listening on %d address%s", nsockfd, (nsockfd == 1) ? "" : "es");
+
+       fds = calloc(nsockfd, sizeof(struct pollfd));
+       for (i = 0; i < nsockfd; i++) {
+               fds[i].fd = sockfdlist[i];
+               fds[i].events = POLLIN;
+       }
+       timeout.tv_sec = MAIN_LOOP_TIMEOUT;
+       timeout.tv_nsec = 0;
+
+       sigfillset(&sigmask);
+       sigdelset(&sigmask, SIGTERM);
+       sigdelset(&sigmask, SIGINT);
+
+       terminate = 0;
+       while (!terminate) {
+               int r;
+
+               r = ppoll(fds, nsockfd, &timeout, &sigmask);
+               if (r < 0) {
+                       dbg("%s", strerror(errno));
+                       terminate = 1;
+               } else if (r) {
+                       for (i = 0; i < nsockfd; i++) {
+                               if (fds[i].revents & POLLIN) {
+                                       dbg("read event on fd[%d]=%d",
+                                           i, sockfdlist[i]);
+                                       process_request(sockfdlist[i]);
+                               }
+                       }
+               } else {
+                       dbg("heartbeat timeout on ppoll()");
+               }
+       }
+
+       info("shutting down " PROGNAME);
+       free(fds);
+       usbip_host_driver_close();
+
+       return 0;
+}
+
+int main(int argc, char *argv[])
+{
+       static const struct option longopts[] = {
+               { "ipv4",     no_argument,       NULL, '4' },
+               { "ipv6",     no_argument,       NULL, '6' },
+               { "daemon",   no_argument,       NULL, 'D' },
+               { "daemon",   no_argument,       NULL, 'D' },
+               { "debug",    no_argument,       NULL, 'd' },
+               { "pid",      optional_argument, NULL, 'P' },
+               { "tcp-port", required_argument, NULL, 't' },
+               { "help",     no_argument,       NULL, 'h' },
+               { "version",  no_argument,       NULL, 'v' },
+               { NULL,       0,                 NULL,  0  }
+       };
+
+       enum {
+               cmd_standalone_mode = 1,
+               cmd_help,
+               cmd_version
+       } cmd;
+
+       int daemonize = 0;
+       int ipv4 = 0, ipv6 = 0;
+       int opt, rc = -1;
+
+       pid_file = NULL;
+
+       usbip_use_stderr = 1;
+       usbip_use_syslog = 0;
+
+       if (geteuid() != 0)
+               err("not running as root?");
+
+       cmd = cmd_standalone_mode;
+       for (;;) {
+               opt = getopt_long(argc, argv, "46DdP::t:hv", longopts, NULL);
+
+               if (opt == -1)
+                       break;
+
+               switch (opt) {
+               case '4':
+                       ipv4 = 1;
+                       break;
+               case '6':
+                       ipv6 = 1;
+                       break;
+               case 'D':
+                       daemonize = 1;
+                       break;
+               case 'd':
+                       usbip_use_debug = 1;
+                       break;
+               case 'h':
+                       cmd = cmd_help;
+                       break;
+               case 'P':
+                       pid_file = optarg ? optarg : DEFAULT_PID_FILE;
+                       break;
+               case 't':
+                       usbip_setup_port_number(optarg);
+                       break;
+               case 'v':
+                       cmd = cmd_version;
+                       break;
+               case '?':
+                       usbipd_help();
+               default:
+                       goto err_out;
+               }
+       }
+
+       if (!ipv4 && !ipv6)
+               ipv4 = ipv6 = 1;
+
+       switch (cmd) {
+       case cmd_standalone_mode:
+               rc = do_standalone_mode(daemonize, ipv4, ipv6);
+               remove_pid_file();
+               break;
+       case cmd_version:
+               printf(PROGNAME " (%s)\n", usbip_version_string);
+               rc = 0;
+               break;
+       case cmd_help:
+               usbipd_help();
+               rc = 0;
+               break;
+       default:
+               usbipd_help();
+               goto err_out;
+       }
+
+err_out:
+       return (rc > -1 ? EXIT_SUCCESS : EXIT_FAILURE);
+}
diff --git a/tools/usb/usbip/src/utils.c b/tools/usb/usbip/src/utils.c
new file mode 100644 (file)
index 0000000..2b3d6d2
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
+ *               2005-2007 Takahiro Hirofuchi
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "usbip_common.h"
+#include "utils.h"
+#include "sysfs_utils.h"
+
+int modify_match_busid(char *busid, int add)
+{
+       char attr_name[] = "match_busid";
+       char command[SYSFS_BUS_ID_SIZE + 4];
+       char match_busid_attr_path[SYSFS_PATH_MAX];
+       int rc;
+
+       snprintf(match_busid_attr_path, sizeof(match_busid_attr_path),
+                "%s/%s/%s/%s/%s/%s", SYSFS_MNT_PATH, SYSFS_BUS_NAME,
+                SYSFS_BUS_TYPE, SYSFS_DRIVERS_NAME, USBIP_HOST_DRV_NAME,
+                attr_name);
+
+       if (add)
+               snprintf(command, SYSFS_BUS_ID_SIZE + 4, "add %s", busid);
+       else
+               snprintf(command, SYSFS_BUS_ID_SIZE + 4, "del %s", busid);
+
+       rc = write_sysfs_attribute(match_busid_attr_path, command,
+                                  sizeof(command));
+       if (rc < 0) {
+               dbg("failed to write match_busid: %s", strerror(errno));
+               return -1;
+       }
+
+       return 0;
+}
diff --git a/tools/usb/usbip/src/utils.h b/tools/usb/usbip/src/utils.h
new file mode 100644 (file)
index 0000000..5916fd3
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
+ *               2005-2007 Takahiro Hirofuchi
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __UTILS_H
+#define __UTILS_H
+
+int modify_match_busid(char *busid, int add);
+
+#endif /* __UTILS_H */
+
index bf06577fea51c22ab944edb9560e56f01aae2f94..5819a2708d7edd5823d9e5885a6b7c3796b387ad 100644 (file)
@@ -526,8 +526,10 @@ static int assign_guest_irq(struct kvm *kvm,
                dev->irq_requested_type |= guest_irq_type;
                if (dev->ack_notifier.gsi != -1)
                        kvm_register_irq_ack_notifier(kvm, &dev->ack_notifier);
-       } else
+       } else {
                kvm_free_irq_source_id(kvm, dev->irq_source_id);
+               dev->irq_source_id = -1;
+       }
 
        return r;
 }
index 0df7d4b34dfec96345d359bf08562309d8607f40..714b949323120aee855dd7e57db549cac31e8183 100644 (file)
@@ -61,6 +61,14 @@ static pfn_t kvm_pin_pages(struct kvm_memory_slot *slot, gfn_t gfn,
        return pfn;
 }
 
+static void kvm_unpin_pages(struct kvm *kvm, pfn_t pfn, unsigned long npages)
+{
+       unsigned long i;
+
+       for (i = 0; i < npages; ++i)
+               kvm_release_pfn_clean(pfn + i);
+}
+
 int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot)
 {
        gfn_t gfn, end_gfn;
@@ -123,6 +131,7 @@ int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot)
                if (r) {
                        printk(KERN_ERR "kvm_iommu_map_address:"
                               "iommu failed to map pfn=%llx\n", pfn);
+                       kvm_unpin_pages(kvm, pfn, page_size);
                        goto unmap_pages;
                }
 
@@ -134,7 +143,7 @@ int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot)
        return 0;
 
 unmap_pages:
-       kvm_iommu_put_pages(kvm, slot->base_gfn, gfn);
+       kvm_iommu_put_pages(kvm, slot->base_gfn, gfn - slot->base_gfn);
        return r;
 }
 
@@ -266,14 +275,6 @@ out_unlock:
        return r;
 }
 
-static void kvm_unpin_pages(struct kvm *kvm, pfn_t pfn, unsigned long npages)
-{
-       unsigned long i;
-
-       for (i = 0; i < npages; ++i)
-               kvm_release_pfn_clean(pfn + i);
-}
-
 static void kvm_iommu_put_pages(struct kvm *kvm,
                                gfn_t base_gfn, unsigned long npages)
 {